Prepare data for various DGE analyses

Get situated

Load necessary libraries

library(DESeq2)
library(edgeR)
library(EnhancedVolcano)
library(GenomicRanges)
library(ggrepel)
library(IRanges)
library(PCAtools)
library(readxl)
library(tidyverse)


Set working directory

# p_local <- "/Users/kalavattam/Dropbox/FHCC"  # KrisMac
p_local <- "/Users/kalavatt/projects-etc"  # WorkMac
p_wd <- "2022_transcriptome-construction/results/2023-0215"
#NOTE 1/3 Alison: you can adjust 'p_local' or 'p_wd' (path to working directory 
#NOTE 2/3 on your personal or work computer ); I have two paths here with one
#NOTE 3/3 commented out depending on which computer I am using

setwd(paste(p_local, p_wd, sep = "/"))
getwd()
rm(p_local, p_wd)


Set options

  • Use normal numbers instead of default scientific numbers in plots
  • Do not limit number of overlaps when including labels in plots
options(scipen=999)
options(ggrepel.max.overlaps = Inf)


Initialize necessary functions

split_isolate_convert <- function(in_vector, field, column_name) {
    # Take in a character vector of S288C R64-1-1 feature names and split
    # elements at the underscores that separate feature names from
    # classifications, e.g., "YER043_mRNA-E1" is split at the underscore. User
    # has the option to return either the first (feature name) or second
    # (classification) value in a tibble data type. User must also input a
    # name for the column in the tibble.
    #
    # :param in_vector: character vector of S288C R64-1-1 feature names [vec]
    # :param field: first or second string separated by underscore
    #               [int = 1 | int = 2]
    # :param column_name: name of column in tibble [chr]
    # :return out_df: tibble of first or second strings separated by underscore
    #                 [tbl]
    out_df <- in_vector %>%
        stringr::str_split(., c("_")) %>%
        sapply(., "[", field) %>%
        as.data.frame() %>%
        tibble::as_tibble()
    
    colnames(out_df) <- column_name
    
    return(out_df)
}
#TODO Add return description


plot_volcano <- function(
    table, label, selection, label_size, p_cutoff, FC_cutoff,
    xlim, ylim, color, title, subtitle, ...
) {
    #TODO Write a description of this function
    #
    # :param table: dataframe of test statistics [df]
    # :param label: character vector of all variable names in param table [vec]
    # :param selection: character vector of selected variable names in param
    #                   table [vec]
    # :param label_size: size of label font [float]
    # :param p_cutoff: cut-off for statistical significance; a horizontal line
    #                  will be drawn at -log10(pCutoff); p is actually padj
    #                  [float]
    # :param FC_cutoff: cut-off for absolute log2 fold-change; vertical lines
    #                   will be drawn at the negative and positive values of
    #                   log2FCcutoff
    #                  [float]
    # :param xlim: limits of the x-axis [float]
    # :param ylim: limits of the y-axis [float]
    # :param color: color of DEGs, e.g., '#52BE9B' [hex]
    # :param title: plot title [chr]
    # :param subtitle: plot subtitle [chr]
    # :return volcano: ...
    volcano <- EnhancedVolcano::EnhancedVolcano(
        toptable = table,
        lab = label,
        selectLab = selection,
        x = "log2FoldChange",
        y = "padj",
        xlab = "log2(FC)",
        ylab = "-log10(padj)",
        pCutoff = p_cutoff,
        pCutoffCol = "padj",
        FCcutoff = FC_cutoff,
        xlim = xlim,
        ylim = ylim,
        cutoffLineType = "dashed",
        cutoffLineWidth = 0.2,
        pointSize = 1,
        shape = 16,
        colAlpha = 0.25,
        col = c('#D3D3D3', '#D3D3D3', '#D3D3D3', color),
        title = NULL,
        subtitle = NULL,
        caption = NULL,
        borderColour = "#000000",
        borderWidth = 0.2,
        gridlines.major = TRUE,
        gridlines.minor = TRUE,
        axisLabSize = 10,
        labSize = label_size,
        boxedLabels = TRUE,
        parseLabels = TRUE,
        drawConnectors = TRUE,
        widthConnectors = 0.2,
        colConnectors = 'black',
        max.overlaps = Inf
    ) +
        theme_slick_no_legend +
        ggplot2::ggtitle(title, subtitle = subtitle)
    return(volcano)
}
#TODO Add return description


save_volcano <- function(plot, file, width, height) {
    #TODO Write a description of this function
    #
    # :param plot: ...
    # :param file: ...
    # :param width: ...
    # :param height: ...
    # :return: ...
    ggplot2::ggsave(
        plot,
        filename = file,
        device = "pdf",
        h = width,
        w = height,
        units = "in"
    )
}
#TODO Add return description


get_name_of_var <- function(v) {
    #TODO Write a description of this function
    #
    # :param v: ...
    # :return v: ...
    return(deparse(substitute(v)))
}
#TODO Add return description


get_top_loadings <- function(x, y, z, a) {
    #TODO Write a description of this function
    #
    # :param x: dataframe of PC loadings <data.frame>
    # :param y: character element for column in dataframe x <chr>
    # :param z: whether to select all loadings sorted from largest to smallest
    #           absolute value ('all'), positive loadings sorted from largest
    #           to smallest value ('pos'), or negative loadings sorted from
    #           largest to smallest absolute value ('neg') <str>
    # :param a: whether or not to keep 'sign' and 'abs' columns added in the
    #           course of processing the dataframe <logical>
    # :return b: ...
    b <- as.data.frame(x[[y]])
    rownames(b) <- rownames(x)
    colnames(b) <- y
    
    b[["sign"]] <- ifelse(
        b[[y]] > 0,
        "pos",
        ifelse(
            b[[y]] == 0,
            "zero",
            "neg"
        )
    )
    
    b[["abs"]] <- abs(b[[y]])
    
    if(z == "all") {
        b <- dplyr::arrange(b, by = desc(abs))
    } else if(z == "pos") {
        b <- b[b[[y]] > 0, ] %>% dplyr::arrange(., by = desc(abs))
    } else if(z == "neg") {
        b <- b[b[[y]] < 0, ] %>% dplyr::arrange(., by = desc(abs))
    } else {
        stop(paste0("Stopping: param z must be either 'all', 'pos', or 'neg'"))
    }
    
    if(isTRUE(a)) {
        paste0("Retaining 'sign' and 'abs' columns")
    } else if(isFALSE(a)) {
        b <- b %>% dplyr::select(-c(sign, abs))
    } else {
        stop(paste0("Stopping: param a must be either 'TRUE' or 'FALSE'"))
    }
    
    return(b)
}
#TODO Add return description


plot_biplot <- function(
    pca, PC_x, PC_y,
    loadings_show, loadings_n,
    meta_color, meta_shape,
    x_min, x_max, y_min, y_max
) {
    #TODO Write a description of this function
    #
    # :param pca: "pca" list object obtained by running PCAtools::pca()
    # :param PC_x: PC to plot on the x axis <chr>
    # :param PC_y: PC to plot on the y axis <chr>
    # :param loadings_show: whether to overlay component loadings or not <lgl>
    # :param loadings_n: number of top loadings to show <int >= 0>
    # :param meta_color: column in "pca" list metadata to color by <chr>
    # :param meta_shape: column in "pca" list metadata to shape by <chr>
    # :param x_min: minimum value on x axis <dbl>
    # :param x_max: maximum value on x axis <dbl>
    # :param y_min: minimum value on y axis <dbl>
    # :param y_max: maximum value on y axis <dbl>
    # :param title: title of biplot <dbl>
    # :return image: ...
    image <- pca %>% 
        PCAtools::biplot(
            x = PC_x,
            y = PC_y,
            lab = NULL,
            showLoadings = loadings_show,
            ntopLoadings = loadings_n,
            boxedLoadingsNames = TRUE,
            colby = meta_color,
            shape = meta_shape,
            encircle = FALSE,
            ellipse = FALSE,
            max.overlaps = Inf,
            xlim = c(x_min, x_max),
            ylim = c(y_min, y_max)
        ) +
            theme_slick
    
    return(image)
}
#TODO Add return description


plot_pos_neg_loadings_each_axis <- function(
    df_all, df_pos, df_neg,
    PC_x, PC_y,
    row_start, row_end,
    x_min, x_max, y_min, y_max,
    x_nudge, y_nudge, x_label, y_label,
    col_line_pos, col_line_neg, col_seg_pos, col_seg_neg
) {
    #TODO Write a description of this function
    #
    # :param df_all: dataframe: all loadings (from, e.g., PCAtools)
    # :param df_pos: dataframe: positive loadings ordered largest to smallest
    # :param df_neg: dataframe: negative loadings ordered smallest to largest
    # :param PC_x: PC to plot on the x axis
    # :param PC_y: PC to plot on the y axis
    # :param row_start: row from which to begin subsetting the PCs on x and y
    # :param row_end: row at which to end subsetting the PCs on x and y
    # :param x_min: minimum value on x axis <dbl>
    # :param x_max: maximum value on x axis <dbl>
    # :param y_min: minimum value on y axis <dbl>
    # :param y_max: maximum value on y axis <dbl>
    # :param x_nudge: amount to nudge labels on the x axis <dbl>
    # :param y_nudge: amount to nudge labels on the y axis <dbl>
    # :param x_label: x axis label <chr>
    # :param y_label: y axis label <chr>
    # :param col_line_pos: color: lines, arrows for positive loadings <chr>
    # :param col_line_neg: color: lines, arrows for negative loadings <chr>
    # :param col_seg_pos: color: segments connecting arrowhead and text bubble
    #                     for positive loadings <chr>
    # :param col_seg_neg: color: segments connecting arrowhead and text bubble
    #                     for negative loadings <chr>
    # :return image: ...
    filter_pos_1 <- rownames(df_pos[[PC_x]][row_start:row_end, ])
    filter_pos_2 <- rownames(df_pos[[PC_y]][row_start:row_end, ])
    filter_neg_1 <- rownames(df_neg[[PC_x]][row_start:row_end, ])
    filter_neg_2 <- rownames(df_neg[[PC_y]][row_start:row_end, ])
    
    loadings_filter_pos_1 <- df_all[rownames(df_all) %in% filter_pos_1, ]
    loadings_filter_pos_2 <- df_all[rownames(df_all) %in% filter_pos_2, ]
    loadings_filter_neg_1 <- df_all[rownames(df_all) %in% filter_neg_1, ]
    loadings_filter_neg_2 <- df_all[rownames(df_all) %in% filter_neg_2, ]
    
    images <- list()
    images[["PC_x_pos"]] <- plot_loadings(
        loadings_filter_pos_1,
        loadings_filter_pos_1[[PC_x]],
        loadings_filter_pos_1[[PC_y]],
        x_min, x_max, y_min, y_max, x_nudge, y_nudge,
        x_label, y_label, col_line_pos, col_seg_pos
    )
    images[["PC_y_pos"]] <- plot_loadings(
        loadings_filter_pos_2,
        loadings_filter_pos_2[[PC_x]],
        loadings_filter_pos_2[[PC_y]],
        x_min, x_max, y_min, y_max, x_nudge, y_nudge,
        x_label, y_label, col_line_pos, col_seg_pos
    )
    images[["PC_x_neg"]] <- plot_loadings(
        loadings_filter_neg_1,
        loadings_filter_neg_1[[PC_x]],
        loadings_filter_neg_1[[PC_y]],
        x_min, x_max, y_min, y_max, -y_nudge, x_nudge,
        x_label, y_label, col_line_neg, col_seg_neg
    )
    images[["PC_y_neg"]] <- plot_loadings(
        loadings_filter_neg_2,
        loadings_filter_neg_2[[PC_x]],
        loadings_filter_neg_2[[PC_y]],
        x_min, x_max, y_min, y_max, x_nudge, -y_nudge,
        x_label, y_label, col_line_neg, col_seg_neg
    )
    return(images)
}
#TODO Add return description


plot_loadings <- function(x, y, z, a, b, d, e, f, g, h, i, j, k) {
    #TODO Write a description of this function
    #
    # :param x: dataframe of PC loadings w/gene names as rownames <data.frame>
    # :param y: column in dataframe to plot on x axis <dbl>
    # :param z: column in dataframe to plot on y axis <dbl>
    # :param a: minimum value on x axis <dbl>
    # :param b: maximum value on x axis <dbl>
    # :param d: minimum value on y axis <dbl>
    # :param e: maximum value on y axis <dbl>
    # :param f: amount to nudge labels on the x axis <dbl>
    # :param g: amount to nudge labels on the y axis <dbl>
    # :param h: x axis label <chr>
    # :param i: y axis label <chr>
    # :param j: color of line and arrow <chr>
    # :param k: color of segment connecting arrowhead and text bubble <chr>
    # :return l: ...
    l <- ggplot2::ggplot(x, ggplot2::aes(x = y, y = z)) +  #TODO #FUNCTION
        ggplot2::coord_cartesian(xlim = c(a, b), ylim = c(d, e)) +
        ggplot2::geom_segment(
            aes(xend = 0, yend = 0, alpha = 0.5),
            color = j, 
            arrow = ggplot2::arrow(
                ends = "first",
                type = "open",
                length = unit(0.125, "inches")
            )
        ) +
        ggrepel::geom_label_repel(
            mapping = ggplot2::aes(
                fontface = 1, segment.color = k, segment.size = 0.25
            ),
            label = rownames(x),
            label.size = 0.05,
            direction = "both",
            nudge_x = f,  # 0.02
            nudge_y = g,  # 0.04
            force = 4,
            force_pull = 1,
            hjust = 0
        ) +
        ggplot2::xlab(h) +
        ggplot2::ylab(i) +
        theme_slick_no_legend
    
    return(l)
}
#TODO Add return description


draw_scree_plot <- function(pca, horn, elbow) {
    #TODO Write a description of this function
    #
    # :param pca: "pca" list object obtained by running PCAtools::pca()
    # :param horn: ...
    # :param elbow: ...
    # :return scree: ...
    scree <- PCAtools::screeplot(
        pca,
        components = PCAtools::getComponents(pca),
        vline = c(horn, elbow),
        vlineWidth = 0.25,
        sizeCumulativeSumLine = 0.5,
        sizeCumulativeSumPoints = 1.5
    ) +
        geom_text(aes(horn + 1, 50, label = "Horn's", vjust = 2)) +
        geom_text(aes(elbow + 1, 50, label = "Elbow", vjust = -2)) +
        theme_slick +
        ggplot2::theme(axis.text.x = element_text(angle = 90, hjust = 1))

    return(scree)
}
#TODO Add return description


#  Set up custom ggplot2 plot themes ------------------------------------------
theme_slick <- theme_classic() +
    theme(
        panel.grid.major = ggplot2::element_line(linewidth = 0.4),
        panel.grid.minor = ggplot2::element_line(linewidth = 0.2),
        axis.line = ggplot2::element_line(linewidth = 0.2),
        axis.ticks = ggplot2::element_line(linewidth = 0.4),
        axis.text = ggplot2::element_text(color = "black"),
        axis.title.x = ggplot2::element_text(),
        axis.title.y = ggplot2::element_text(),
        plot.title = ggplot2::element_text(),
        text = element_text(family = "")
    )

theme_slick_no_legend <- theme_slick + theme(legend.position = "none")


Load in Excel spreadsheet of samples names and variables

The spreadsheet includes Alison’s original sample names; we can use this information to associate the new sample names, which are made up of DESeq2 model variable values, with the old names, which reflect Alison’s wet-lab, library-prep, etc. work

p_xl <- "notebook"  #INPATH
f_xl <- "variables.xlsx"  #INFILE
t_xl <- readxl::read_xlsx(
    paste(p_xl, f_xl, sep = "/"), sheet = "master", na = "NA"
)

rm(p_xl, f_xl)


Load in and process featureCounts table

#  Load in featureCounts table ------------------------------------------------
p_fc <- "outfiles_featureCounts/combined_SC_KL/UT_prim_UMI"  #INPATH
f_fc <- "UT_prim_UMI.featureCounts"  #INFILE
t_fc <- read.table(
    paste(p_fc, f_fc, sep = "/"), header = TRUE, row.names = 1
) %>% 
    tibble::rownames_to_column() %>%
    tibble::as_tibble()

rm(p_fc, f_fc)


#  Clean up tibble column names -----------------------------------------------
colnames(t_fc) <- colnames(t_fc) %>%
    gsub("rowname", "feature_init", .) %>%
    gsub("Chr", "chr", .) %>%
    gsub("Start", "start", .) %>%
    gsub("End", "end", .) %>%
    gsub("Strand", "strand", .) %>%
    gsub("Length", "length", .) %>%
    gsub("bams_renamed\\.UT_prim_UMI\\.", "", .) %>%
    gsub("\\.UT_prim_UMI\\.bam", "", .) %>%
    gsub("\\.d", "-d", .) %>%
    gsub("\\.n", "-n", .) %>%
    gsub("aux\\.", "aux-", .) %>%
    gsub("tc\\.", "tc-", .)


#  Order tibble by chromosome names and feature start positions ---------------
chr_SC <- c(
    "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII",
    "XIII", "XIV", "XV", "XVI", "Mito"
)
chr_KL <- c("A", "B", "C", "D", "E", "F")
chr_order <- c(chr_SC, chr_KL)
t_fc$chr <- t_fc$chr %>% as.factor()
t_fc$chr <- ordered(t_fc$chr, levels = chr_order)

t_fc <- t_fc %>% dplyr::arrange(chr, start)


#  Categorize chromosomes by genome of origin ---------------------------------
t_fc$genome <- ifelse(
    t_fc$chr %in% chr_SC,
    "S_cerevisiae",
    ifelse(
        t_fc$chr %in% chr_KL,
        "K_lactis",
        NA
    )
) %>%
    as.factor()

#  Move the new column "genome" to a better location in the tibble (before
#+ column "chr")
t_fc <- t_fc %>% dplyr::relocate("genome", .before = "chr")

#  Check on variable/column "genome"
levels(t_fc$genome)
t_fc %>%
    dplyr::group_by(genome) %>%
    dplyr::summarize(tally = length(genome))
#  The code returns...
# K_lactis = 5659, S_cerevisiae = 7507

rm(chr_KL, chr_SC, chr_order)


#  Split and better organize variable 'feature_init' --------------------------
#  Split 'feature_init' into two distinct elements (separated by an underscore)
el_1 <- split_isolate_convert(
    in_vector = t_fc$feature_init,
    field = 1,
    column_name = "feature"
)
el_2 <- split_isolate_convert(
    in_vector = t_fc$feature_init,
    field = 2,
    column_name = "type"
)

#  Append split information to tibble 't_fc'
t_fc <- dplyr::bind_cols(t_fc, el_1, el_2) %>%
    dplyr::relocate(c("feature", "type"), .after = "feature_init")

rm(el_1, el_2)

#  Limit the splitting/reorganization to S. cerevisiae features only; the above
#+ splitting/reorganization work isn't appropriate for K. lactis 'feature_init'
#+ information because the K. lactis naming/classification differs from the S.
#+ cerevisiae naming/classification system)
t_fc$feature <- ifelse(
    t_fc$genome == "K_lactis", t_fc$feature_init, t_fc$feature
)
t_fc$type <- ifelse(
    t_fc$genome == "K_lactis", NA, t_fc$type
)

#  Create levels for S. cerevisiae 'type' NAs and K. lactis 'type' NAs, then
#+ factorize variable 'type': essentially, we're making the NAs into levels so
#+ that we can tally them (as below) and/or potentially subset them; however,
#+ before doing so, we're differentiating the NAs by whether they are
#+ associated with S. cerevisiae features or K. lactis features
t_fc$type <-  ifelse(
    (t_fc$genome == "S_cerevisiae" & is.na(t_fc$type)),
    "NA_SC",
    ifelse(
        (t_fc$genome == "K_lactis" & is.na(t_fc$type)),
        "NA_KL",
        t_fc$type
    )
) %>%
    as.factor()

#  Do a quick check of the tibble 't_fc' (where "t_fc" stands for "tibble
#+ featureCounts")
t_fc

#  Check on the split information: This code tallies the numbers features per
#+ classification, where classifications are things like "mRNA-E1", "tRNA-E1",
#+ "NA_SC" (NAs associated with S. cerevisiae), "NA_KL" (NAs associated with K.
#+ lactis), etc.
levels(t_fc$type)  # 19 levels
t_fc %>%
    dplyr::group_by(type) %>%
    dplyr::summarize(tally = length(type))
#  The code returns things like...
#+ mRNA-E1 = 6600, mRNA-E2 = 283, NA_KL = 5547, NA_SC = 103, tRNA-E1 = 299,
#+ tRNA-E2 = 60, etc.


Record tibble t_fc’s positional information in a GRanges object

pos_info will be used in DESeq2 processing, post-processing, etc.

pos_info <- GenomicRanges::GRanges(
    seqnames = t_fc$chr,
    ranges = IRanges::IRanges(t_fc$start, t_fc$end),
    strand = t_fc$strand,
    length = t_fc$length,
    feature = t_fc$feature,
    feature_init = t_fc$feature_init,
    type = t_fc$type,
    genome = t_fc$genome
)
pos_info



Perform normalization and run DGE analyses

Perform prep work

Establish table of variables for dds—i.e., a “master” model matrix

  • dds stands for “DESeq2 dataset” and is a DESeqDataSet object
  • variables for dds are
    • strain
    • state
    • time
    • kit (tcn for “Tecan”, ovn for “Ovation”)
    • transcription (N for “nascent”, SS for “steady state”)
    • auxin
    • timecourse
    • replicate
    • technical
#  Columns ten through to the last column are composed of sample feature
#+ counts; get these column names into a vector
samples <- colnames(t_fc)[10:length(colnames(t_fc))]

#  Convert the vector of column names to a list by splitting each element at
#+ its underscores; thus, each vector element becomes a list of eight strings,
#+ with one string for 'strain', one for 'state', etc.; these 
samples <- stringr::str_split(samples, "_")

#  Convert the list to a dataframe, transpose it, then convert it to a tibble
#+ [R fun fact: 'tibble' data types can't be built directly from 'list' data
#+ types; in fact, it can difficult to build 'dataframe' types from 'list'
#+ types as well; the reason we have no issues doing this is because we have
#+ ensured ahead of time that each list element has the same number of
#+ subelements (8); the difficulty arises when lists elements have varying
#+ numbers of subelements]
samples <- samples %>%
    as.data.frame(
        .,
        #  Using numeric column names here because the columns will soon be
        #+ transposed to rows, and I don't want the rows to have proper names
        col.names = c(seq(1, 62)),
        #  Using proper row names here because the rows will soon be transposed
        #+ to columns, and I *do* want the columns to have proper names 
        row.names = c(
            "strain", "state", "time", "kit", "transcription", "auxin",
            "timecourse", "replicate", "technical"
        )
    ) %>%
    t() %>%
    tibble::as_tibble()

#  Add a keys variable for quickly accessing combinations of variable values
keys <- vector(mode = "character")
for(i in seq(1, nrow(samples))) {
    # i <- 1
    keys[i] <- paste(
        samples[i, 1], samples[i, 2], samples[i, 3],
        samples[i, 4], samples[i, 5], samples[i, 6],
        samples[i, 7], samples[i, 8], samples[i, 9],
        sep = "_"
    )
}
keys <- keys %>% as.data.frame()
colnames(keys) <- "keys"

samples <- dplyr::bind_cols(samples, keys) %>%
    dplyr::relocate("keys", .before = "strain")

rm(i)

#  Add Alison's original samples names to the 'samples' dataframe using the
#+ 't_xl' dataframe; here, we're just adding the original sample names, but we
#+ could potentially add in other information stored in the Excel file
t_xl <- t_xl %>%
    dplyr::rename(keys = name) %>%
    dplyr::select(., c(keys, sample_name))
samples <- dplyr::full_join(samples, t_xl, by = "keys")

# #  Convert all columns to data type 'factor' (having the variable values as
# #+ factors helps with running DESeq2::DESeqDataSetFromMatrix() below)
# samples[sapply(samples, is.character)] <- lapply(
#     samples[sapply(samples, is.character)], as.factor
# )
#TODO Hold off on factor conversion/ordered-factor conversion

#  How does it look?
samples

rm(t_xl, keys)


Begin to assess factor enumeration (rough-draft)

colnames(samples)
# samples$keys
samples$strain %>% as.factor() %>% table()
samples$state %>% as.factor() %>% table()
samples$time %>% as.factor() %>% table()
samples$kit %>% as.factor() %>% table()
samples$transcription %>% as.factor() %>% table()
samples$auxin %>% as.factor() %>% table()
samples$timecourse %>% as.factor() %>% table()
samples$replicate %>% as.factor() %>% table()
samples$technical %>% as.factor() %>% table()
# samples$sample_name %>% as.factor() %>% table()



Identify specific samples to evaluate

#!/bin/bash
#DONTRUN

#  Array of samples sequenced in March, 2023 ----------------------------------
samples_March=(
    "WT_DSp48_day4_tcn_SS_aux-F_tc-T_rep1_tech2"
    "r6-n_DSp48_day4_tcn_SS_aux-F_tc-T_rep2_tech1"
    "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech2"
    "WT_G1_day1_tcn_SS_aux-F_tc-F_rep1_tech1"
    "WT_G1_day1_tcn_SS_aux-F_tc-F_rep2_tech1"
    "r6-n_G1_day1_tcn_SS_aux-F_tc-F_rep1_tech1"
    "r6-n_G1_day1_tcn_SS_aux-F_tc-F_rep2_tech1"
)
# WT_DSp48_day4_tcn_SS_aux-F_tc-T_rep1_tech2    BM10_DSp48_5781_new    SS timecourse: rrp6∆ vs WT
# r6-n_DSp48_day4_tcn_SS_aux-F_tc-T_rep2_tech1    BM12_DSp48_7079    SS timecourse: rrp6∆ vs WT
# r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech2    CW6_7078_day8_Q_SS    Q SS: rrp6∆ vs rtr1∆ vs WT
# WT_G1_day1_tcn_SS_aux-F_tc-F_rep1_tech1    DA1_5781_SS_G1    G1 N: rrp6∆ vs WT
# WT_G1_day1_tcn_SS_aux-F_tc-F_rep2_tech1    DA2_5782_SS_G1    G1 N: rrp6∆ vs WT
# r6-n_G1_day1_tcn_SS_aux-F_tc-F_rep1_tech1    DA3_7078_SS_G1    G1 N: rrp6∆ vs WT
# r6-n_G1_day1_tcn_SS_aux-F_tc-F_rep2_tech1    DA4_7079_SS_G1    G1 N: rrp6∆ vs WT


#  SS timecourse: rrp6∆ vs WT -------------------------------------------------
#+ - work_evaluation-etc_rough-draft_Rrp6-WT_SS_timecourse_groupwise.Rmd  #MADE
#+ - work_evaluation-etc_rough-draft_Rrp6-WT_SS_timecourse_pairwise.Rmd  #MADE
r6_WT_SS_tc=(
    "r6-n_DSm2_day2_tcn_SS_aux-F_tc-T_rep1_tech1"
    "r6-n_DSm2_day2_tcn_SS_aux-F_tc-T_rep2_tech1"
    "r6-n_DSp2_day2_tcn_SS_aux-F_tc-T_rep1_tech1"
    "r6-n_DSp2_day2_tcn_SS_aux-F_tc-T_rep2_tech1"
    "r6-n_DSp24_day3_tcn_SS_aux-F_tc-T_rep1_tech1"
    "r6-n_DSp24_day3_tcn_SS_aux-F_tc-T_rep2_tech1"
    "r6-n_DSp48_day4_tcn_SS_aux-F_tc-T_rep1_tech1"
    "r6-n_DSp48_day4_tcn_SS_aux-F_tc-T_rep2_tech1"
    "WT_DSm2_day2_tcn_SS_aux-F_tc-T_rep1_tech1"
    "WT_DSm2_day2_tcn_SS_aux-F_tc-T_rep2_tech1"
    "WT_DSp2_day2_tcn_SS_aux-F_tc-T_rep1_tech1"
    "WT_DSp2_day2_tcn_SS_aux-F_tc-T_rep2_tech1"
    "WT_DSp24_day3_tcn_SS_aux-F_tc-T_rep1_tech1"
    "WT_DSp24_day3_tcn_SS_aux-F_tc-T_rep2_tech1"
    "WT_DSp48_day4_tcn_SS_aux-F_tc-T_rep1_tech1"
    "WT_DSp48_day4_tcn_SS_aux-F_tc-T_rep1_tech2"
    "WT_DSp48_day4_tcn_SS_aux-F_tc-T_rep2_tech1"
)
# r6-n_DSm2_day2_tcn_SS_aux-F_tc-T_rep1_tech1    Bp3_DSm2_7078
# r6-n_DSm2_day2_tcn_SS_aux-F_tc-T_rep2_tech1    BM3_DSm2_7079
# r6-n_DSp2_day2_tcn_SS_aux-F_tc-T_rep1_tech1    Bp6_DSp2_7078
# r6-n_DSp2_day2_tcn_SS_aux-F_tc-T_rep2_tech1    BM6_DSp2_7079
# r6-n_DSp24_day3_tcn_SS_aux-F_tc-T_rep1_tech1    Bp9_DSp24_7078
# r6-n_DSp24_day3_tcn_SS_aux-F_tc-T_rep2_tech1    BM9_DSp24_7079
# r6-n_DSp48_day4_tcn_SS_aux-F_tc-T_rep1_tech1    Bp12_DSp48_7078
# r6-n_DSp48_day4_tcn_SS_aux-F_tc-T_rep2_tech1    BM12_DSp48_7079
# WT_DSm2_day2_tcn_SS_aux-F_tc-T_rep1_tech1    BM1_DSm2_5781
# WT_DSm2_day2_tcn_SS_aux-F_tc-T_rep2_tech1    Bp1_DSm2_5782
# WT_DSp2_day2_tcn_SS_aux-F_tc-T_rep1_tech1    BM4_DSp2_5781
# WT_DSp2_day2_tcn_SS_aux-F_tc-T_rep2_tech1    Bp4_DSp2_5782
# WT_DSp24_day3_tcn_SS_aux-F_tc-T_rep1_tech1    BM7_DSp24_5781
# WT_DSp24_day3_tcn_SS_aux-F_tc-T_rep2_tech1    Bp7_DSp24_5782
# WT_DSp48_day4_tcn_SS_aux-F_tc-T_rep1_tech1    BM10_DSp48_5781
# WT_DSp48_day4_tcn_SS_aux-F_tc-T_rep1_tech2    BM10_DSp48_5781_new
# WT_DSp48_day4_tcn_SS_aux-F_tc-T_rep2_tech1    Bp10_DSp48_5782


#  G1 N: rrp6∆ vs WT  ---------------------------------------------------------
#+ - work_evaluation-etc_rough-draft_Rrp6-WT_N_G1_pairwise.Rmd  #MADE
r6_WT_G1_N=(
    "r6-n_G1_day1_tcn_SS_aux-F_tc-F_rep1_tech1"
    "r6-n_G1_day1_tcn_SS_aux-F_tc-F_rep2_tech1"
    "WT_G1_day1_tcn_SS_aux-F_tc-F_rep1_tech1"
    "WT_G1_day1_tcn_SS_aux-F_tc-F_rep2_tech1"
)
# r6-n_G1_day1_tcn_SS_aux-F_tc-F_rep1_tech1    DA3_7078_SS_G1
# r6-n_G1_day1_tcn_SS_aux-F_tc-F_rep2_tech1    DA4_7079_SS_G1
# WT_G1_day1_tcn_SS_aux-F_tc-F_rep1_tech1    DA1_5781_SS_G1
# WT_G1_day1_tcn_SS_aux-F_tc-F_rep2_tech1    DA2_5782_SS_G1


#  Q N: rrp6∆ vs rtr1∆ vs WT (no samples from March, 2023) --------------------
#+ - work_evaluation-etc_rough-draft_Rrp6-Rtr1-WT_N_Q_groupwise.Rmd  #MADE
#+ - work_evaluation-etc_rough-draft_Rrp6-Rtr1-WT_N_Q_pairwise.Rmd  #MADE
r6_r1_WT_Q_N=(
    "r6-n_Q_day8_tcn_N_aux-F_tc-F_rep1_tech1"
    "r6-n_Q_day8_tcn_N_aux-F_tc-F_rep2_tech1"
    "r1-n_Q_day8_tcn_N_aux-F_tc-F_rep1_tech1"
    "r1-n_Q_day8_tcn_N_aux-F_tc-F_rep2_tech1"
    "WT_Q_day8_tcn_N_aux-F_tc-F_rep1_tech1"
    "WT_Q_day8_tcn_N_aux-F_tc-F_rep2_tech1"
)
# r6-n_Q_day8_tcn_N_aux-F_tc-F_rep1_tech1    CW6_7078_8day_Q_PD
# r6-n_Q_day8_tcn_N_aux-F_tc-F_rep2_tech1    CW8_7079_8day_Q_PD
# r1-n_Q_day8_tcn_N_aux-F_tc-F_rep1_tech1    CW10_7747_8day_Q_PD
# r1-n_Q_day8_tcn_N_aux-F_tc-F_rep2_tech1    CW12_7748_8day_Q_PD
# WT_Q_day8_tcn_N_aux-F_tc-F_rep1_tech1    CW2_5781_8day_Q_PD
# WT_Q_day8_tcn_N_aux-F_tc-F_rep2_tech1    CW4_5782_8day_Q_PD


#  Q SS: rrp6∆ vs rtr1∆ vs WT -------------------------------------------------
#+ - work_evaluation-etc_rough-draft_Rrp6-Rtr1-WT_SS_Q_groupwise.Rmd  #MADE
#+ - work_evaluation-etc_rough-draft_Rrp6-Rtr1-WT_SS_Q_pairwise.Rmd  #MADE
r6_r1_WT_Q_SS=(
    "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1"
    "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech2"
    "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1"
    "r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1"
    "r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1"
    "WT_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1"
    "WT_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1"
)
# r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1    CW6_7078_8day_Q_IN
# r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech2    CW6_7078_day8_Q_SS
# r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1    CW8_7079_8day_Q_IN
# r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1    CW10_7747_8day_Q_IN
# r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1    CW12_7748_8day_Q_IN
# WT_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1    CW2_5781_8day_Q_IN
# WT_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1    CW4_5782_8day_Q_IN


#  Tests of the Tecan kit (no samples from March, 2023) -----------------------
test_Tecan_WT=(
    "WT_Q_day7_tcn_N_aux-F_tc-F_rep2_tech1"
    "WT_Q_day7_tcn_SS_aux-F_tc-F_rep2_tech1"
)
# WT_Q_day7_tcn_N_aux-F_tc-F_rep2_tech1    CU11_5782_Q_Nascent
# WT_Q_day7_tcn_SS_aux-F_tc-F_rep2_tech1    CU12_5782_Q_SteadyState



Do prep work with “Q SS: rrp6∆ vs rtr1∆ vs WT

For datasets_all, make the counts matrix

datasets_all <- c(
    "WT_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
    "WT_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1",
    "r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
    "r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1",
    "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
    "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech2",
    "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1"
)
# datasets_r1_r6 <- c(
#     "r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
#     "r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1",
#     "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
#     "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech2",
#     "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1"
# )
# datasets_WT_r6 <- c(
#     "WT_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
#     "WT_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1",
#     "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
#     "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech2",
#     "r6-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1"
# )
# datasets_WT_r1 <- c(
#     "r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
#     "r1-n_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1",
#     "WT_Q_day8_tcn_SS_aux-F_tc-F_rep1_tech1",
#     "WT_Q_day8_tcn_SS_aux-F_tc-F_rep2_tech1"
# )

#  For now, focus on datasets_all
datasets <- datasets_all  #IMPORTANT #COMEBACKTOTHIS
counts_data <- t_fc[, colnames(t_fc) %in% datasets] %>%
    as.data.frame()

#  How do things look?
counts_data


For datasets_all, make the model matrix

#  Use the "keys" column to isolate datasets of interest
#REMEMBER Variable `datasets` is initialized in the preceding chunk 
col_data <- samples[samples$keys %in% datasets, ] %>%
    as.data.frame() %>%  #IMPORTANT Output a dataframe, not a tibble
    tibble::column_to_rownames(., var = "keys") %>%  #IMPORTANT Have row names
    droplevels() 

#  Make Rrp6-null numerator, wild-type denominator by explicitly reordering the
#+ levels of the factor col_data$strain
col_data$strain <- factor(col_data$strain, levels = c("WT", "r1-n", "r6-n"))

#  Explicitly reorder the levels of the col_data$technical
col_data$technical <- factor(col_data$technical, levels = c("tech1", "tech2"))

#  How do things look?
col_data
col_data$strain


For datasets_all, continue factor enumeration (rough-draft)

# #  Survey the levels associated with model variables
# colnames(col_data)
# col_data$strain %>% as.factor() %>% table()
# col_data$replicate %>% as.factor() %>% table()
# col_data$technical %>% as.factor() %>% table()

#  Transform the "format" of factors from names to positive integers with
#+ sapply(), which applies the switch() function to each element
col_data$no_strain <- sapply(
    as.character(col_data$strain),
    switch,
    "WT" = 1,
    "r1-n" = 2,
    "r6-n" = 3,
    USE.NAMES = FALSE
)

col_data$no_replicate <- sapply(
    as.character(col_data$replicate),
    switch,
    "rep1" = 1,
    "rep2" = 2,
    USE.NAMES = FALSE
)

col_data$no_technical <- sapply(
    as.character(col_data$technical),
    switch,
    "tech1" = 1,
    "tech2" = 2,
    USE.NAMES = FALSE
)

#  How do things look?
col_data


For datasets_all, make the DESeqDataSet, dds

  • Use counts_data for the featureCount tallies
  • Use col_data for setting up the GLM
  • Use pos_info for adding feature metadata, subsequent subsetting, etc.
dds <- DESeq2::DESeqDataSetFromMatrix(
    countData = counts_data,
    colData = col_data,
    design = ~ 1,
    rowRanges = pos_info
)

#  Make a back-up of the DESeqDataSet object
bak.dds <- dds

# #  How do things look?
# dds %>% BiocGenerics::counts() %>% head()
# dds@rowRanges
# dds@design
# dds@assays

# #  For tests
# rm(dds)


Prefilter dds

We probably don’t need to do this, but then again we may want to. Some people think it’s important; my thinking has been that, if it makes much of a difference (e.g., from doing dimension reduction, hierarchical clustering, etc.), then there may be deeper problems with the data (noise, batch effects, etc.). If I remember correctly, if you work through sections of the DESeq2 vignette and other vignettes/walkthroughs (e.g., Soneson et al., F1000), they perform some row-wise prefiltering.

#TODO Let’s keep this in mind and try it if we come to think lowly expressed genes are skewing results.

# threshold <- 1000
# dds_filt <- dds[rowSums(BiocGenerics::counts(dds)) >= threshold, ]
#
#  Breakdown
#    0 13166
#    1 12787
#    2 12711
#    5 12518
#   10 12292
#   20 12017
#   50 11529
#  100 11136
#  200 10653
#  500 9678
# 1000 8462
#
# rm(threshold, dds_filt)



I. Run groupwise analyses

Generate normalized counts

Calculate vst-normalized (unblinded) counts

vsd <- DESeq2::vst(
    dds[dds@rowRanges$genome == "S_cerevisiae", ],
    blind = FALSE
)

norm_v <- limma::removeBatchEffect(
    SummarizedExperiment::assay(vsd),
    batch = vsd$technical,
    design = model.matrix(~strain, SummarizedExperiment::colData(vsd))
) %>% 
    as.data.frame()
norm_v$feature_init <- dds@rowRanges$feature_init[
    dds@rowRanges$genome == "S_cerevisiae"
]

#  Associate normalized values with feature metadata
norm_v <- dplyr::full_join(
    norm_v,
    t_fc[t_fc$genome == "S_cerevisiae", 1:9],
    by = "feature_init"
) %>%
    dplyr::as_tibble()

rm(vsd)

# #PREVIOUS
# norm_v <- DESeq2::vst(
#     dds[dds@rowRanges$genome == "S_cerevisiae", ],
#     blind = FALSE
# ) %>%
#     SummarizedExperiment::assay() %>%
#     as.data.frame()
# norm_v$feature_init <- dds@rowRanges$feature_init[
#     dds@rowRanges$genome == "S_cerevisiae"
# ]
# 
# #  Associate normalized values with feature metadata
# norm_v <- dplyr::full_join(
#     norm_v,
#     t_fc[t_fc$genome == "S_cerevisiae", 1:9],
#     by = "feature_init"
# ) %>%
#     dplyr::as_tibble()


Calculate rlog-normalized (unblinded) counts

rld <- DESeq2::rlog(
    dds[dds@rowRanges$genome == "S_cerevisiae", ],
    blind = FALSE
)

norm_r <- limma::removeBatchEffect(
    SummarizedExperiment::assay(rld),
    batch = rld$technical,
    design = model.matrix(~strain, SummarizedExperiment::colData(rld))
) %>% 
    as.data.frame()
norm_r$feature_init <- dds@rowRanges$feature_init[
    dds@rowRanges$genome == "S_cerevisiae"
]

#  Associate normalized values with feature metadata
norm_r <- dplyr::full_join(
    norm_r,
    t_fc[t_fc$genome == "S_cerevisiae", 1:9],
    by = "feature_init"
) %>%
    dplyr::as_tibble()

rm(rld)

# #PREVIOUS
# norm_r <- DESeq2::rlog(
#     dds[dds@rowRanges$genome == "S_cerevisiae", ],
#     blind = FALSE
# ) %>%
#     SummarizedExperiment::assay() %>%
#     as.data.frame()
# norm_r$feature_init <- dds@rowRanges$feature_init[
#     dds@rowRanges$genome == "S_cerevisiae"
# ]
# 
# #  Associate normalized values with feature metadata
# norm_r <- dplyr::full_join(
#     norm_r,
#     t_fc[t_fc$genome == "S_cerevisiae", 1:9],
#     by = "feature_init"
# ) %>%
#     dplyr::as_tibble()


Calculate GeTMM-normalized counts

More details on this relatively new method of normalization, which combines inter- and intra-sample normalization methods and (appears to) perform quite well:

# #PREVIOUS
# #  Isolate raw counts for samples of interest
# raw <- dds %>%
#     SummarizedExperiment::assay() %>%
#     as.data.frame()
# raw$feature_init <- dds@rowRanges$feature_init
# 
# #  Associate non-normalized values with feature metadata
# raw <- dplyr::full_join(
#     raw,
#     t_fc[, c(seq(1,9))],
#     by = "feature_init"
# ) %>%
#     dplyr::as_tibble()
# 
# #  Calculate counts per kb of gene length (i.e., correct counts for gene
# #+ length); gene length is initially in bp and converted to kb
# rpk <- ((raw[, 1:17] * 10^3) / raw$length)
# rpk[, 18:26] <- raw[, 18:26]
# 
# #  Calculate normalization factors using the raw spike-in (K. lactis) counts
# norm_KL <- edgeR::calcNormFactors(
#     raw[(rpk$genome == "K_lactis"), ][, 1:17]
# )
# 
# #  Create factor for categories (groups)
# model_variables <- stringr::str_split(colnames(rpk[, 1:17]), "_") %>%
#     as.data.frame(
#         row.names = c(
#             "sample", "stage", "day", "kit", "tx", "aux", "tc", "rep", "tech"
#         ),
#         col.names = paste0("s", c(1:17))
#     ) %>%
#     t() %>%
#     tibble::as_tibble()
# 
# group <- factor(
#     # Second level is numerator, first level is denominator
#     model_variables$sample,
#     levels = c("WT", "r6-n")
# )
# 
# rm(model_variables)
# 
# #  Create edgeR DGEList object composed of S. cerevisiae counts per kb gene
# #+ length
# dgel <- edgeR::DGEList(
#     counts = rpk[rpk$genome == "S_cerevisiae", ][, 1:17],
#     group = group
# )
# 
# #  In the DGEList object, include the normalization factors calculated from
# #+ spike-in information
# dgel$samples$norm.factors <- norm_KL
# 
# #  Check that the normalization factors for each library are appropriately
# #+ assigned
# dgel$samples
# 
# #  Scale the values to counts-per-million
# norm_g <- edgeR::cpm(dgel) %>% tibble::as_tibble()
# norm_g[, 18:26] <- rpk[rpk$genome == "S_cerevisiae", 18:26]
# norm_g
# 
# #  Clean up unneeded variables
# rm(raw, rpk, norm_KL, group)
# rm(dgel)  #TODO Delete dgel? Or use it for trying out DE analyses with edgeR?


Calculate TPM-normalized counts

# #PREVIOUS
# #  Isolate raw counts for samples of interest
# raw <- dds %>%
#     SummarizedExperiment::assay() %>%
#     as.data.frame()
# raw$feature_init <- dds@rowRanges$feature_init
# 
# #  Associate non-normalized values with feature metadata
# raw <- dplyr::full_join(
#     raw,
#     t_fc[, 1:9],
#     by = "feature_init"
# ) %>%
#     dplyr::as_tibble()
# 
# #  Calculate counts per kb of gene length (i.e., correct counts for gene
# #+ length or do an "RPK normalization"); then, divide RPK-normalized elements
# #+ by the sum of sample RPK divided by one million: this does the actual TPM
# #+ normalization
# rpk <- tpm <- ((raw[, 1:17] * 10^3) / raw$length)
# for (i in 1:ncol(rpk)) {
#     tpm[, i] <- (rpk[, i] / sum(rpk[, i] / 1e6))
# }
# 
# tpm[, 18:26] <- raw[, 18:26]
# norm_t <- tpm[tpm$genome == "S_cerevisiae", ]
# 
# rm(raw, rpk, tpm)
# 
# #CHECK
# #  Check that my calculation above is actually producing TPM-normalized values:
# #+ #QUESTION 1/2 Do my values match the output from code by Mike Love (author
# #+ #QUESTION 2/2 of DESeq2) posted at support.bioconductor.org/p/91218/?
# # x <- raw[, 1:5] / raw$length
# # test <- t((t(x) * 1e6) / colSums(x))
# # test <- test %>% as.data.frame()
# # identical(
# #       round(test$`n3-d_Q_day7_tcn_N_aux-T_tc-F_rep1_tech1`, digits = 3),
# #     round(norm_t$`n3-d_Q_day7_tcn_N_aux-T_tc-F_rep1_tech1`, digits = 3)
# # )  # [1] TRUE
# #  #ANSWER Basically, the calculations result in equivalent results


Run PCA with variously normalized counts

Part 1

#  Make the following code generic --------------------------------------------
#+ ...so that we can try it with different normalization objects (counts
#+ normalized in different ways)
# norm <- norm_v
norm <- norm_r
# norm <- norm_g
# norm <- norm_t
#NOTE 1/3 norm_g and norm_t appear to be the best performing; norm_r (blinded
#NOTE 2/3 or not) clusters all samples together regardless of model variable
#NOTE 3/3 'strain'

#  Create a PCAtools "pca" S4 object for the normalized counts ----------------
#+ Assign unique row names too
obj_pca <- PCAtools::pca(
    norm[, 1:7],
    metadata = dds[dds@rowRanges$genome != "K_lactis", ]@colData
)
rownames(obj_pca$loadings) <- make.names(
    dds[dds@rowRanges$genome != "K_lactis", ]@rowRanges$feature,
    unique = TRUE
)
# colnames(obj_pca$loadings)


#  Determine "significant" PCs with Horn's parallel analysis ------------------
#+ See Horn, 1965
horn <- PCAtools::parallelPCA(mat = norm[, 1:7])
Warning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than availableWarning: more singular values/vectors requested than available
# horn$n


#  Determine "significant" principle components with the elbow method ---------
#+ See Buja and Eyuboglu, 1992
elbow <- PCAtools::findElbowPoint(obj_pca$variance)
# elbow


#  Evaluate cumulative proportion of explained variance with a scree plot -----
scree <- draw_scree_plot(obj_pca, horn = horn$n, elbow = elbow)
scree

# save_title <- paste0("panel-plot", ".", "scree", ".pdf")
# ggplot2::ggsave(paste0(args$directory_out, "/", save_title), scree)
#TODO Work up some logic for location(s) for outfiles


Part 2

images$PCAtools.PC1.v.PC2
images$KA.PC1.v.PC2$PC_x_pos

images$KA.PC1.v.PC2$PC_x_neg

images$KA.PC1.v.PC2$PC_y_pos

images$KA.PC1.v.PC2$PC_y_neg


Part 3

# for(i in 1:length(names(images))) {
#     # i <- 2
#     vector_names <- names(images) %>% stringr::str_split("\\.")
#     
#     if(vector_names[[i]][1] == "PCAtools") {
#         save_title <- paste0("panel-plot", ".", names(images)[i], ".pdf")
#         ggplot2::ggsave(
#             paste0(args$directory_out, "/", save_title), images[[i]]
#         )
#     } else if(vector_names[[i]][1] == "KA") {
#         save_title <- paste0(
#             "panel-plot", ".", names(images)[i], ".1-x-positive.pdf"
#         )
#         ggplot2::ggsave(
#             paste0(args$directory_out, "/", save_title), images[[i]][[1]]
#         )
#         
#         save_title <- paste0(
#             "panel-plot", ".", names(images)[i], ".2-y-positive.pdf"
#         )
#         ggplot2::ggsave(
#             paste0(args$directory_out, "/", save_title), images[[i]][[2]]
#         )
#         
#         save_title <- paste0(
#             "panel-plot", ".", names(images)[i], ".3-x-negative.pdf"
#         )
#         ggplot2::ggsave(
#             paste0(args$directory_out, "/", save_title), images[[i]][[3]]
#         )
#         
#         save_title <- paste0(
#             "panel-plot", ".", names(images)[i], ".4-y-negative.pdf"
#         )
#         ggplot2::ggsave(
#             paste0(args$directory_out, "/", save_title), images[[i]][[4]]
#         )
#     }
# }
#TODO Work up some logic for location(s) for outfiles


#  Plot the top features on an axis of component loading range ----------------
#+ ...to visualize the top variables (features) that drive variance among
#+ principal components of interest
p_loadings <- PCAtools::plotloadings(
    obj_pca,
    components = getComponents(obj_pca, 1),
    # components = getComponents(obj_pca, 1:5),
    rangeRetain = 0.05,
    absolute = FALSE,
    col = c("#785EF075", "#FFFFFF75", "#FE610075"),
    title = "Loadings plot",
    subtitle = "Top 5% of variables (i.e., features)",
    # shapeSizeRange = c(4, 16),
    borderColour = "#000000",
    borderWidth = 0.2,
    gridlines.major = TRUE,
    gridlines.minor = TRUE,
    axisLabSize = 10,
    labSize = 3,  # label_size
    drawConnectors = TRUE,
    widthConnectors = 0.2,
    typeConnectors = 'closed',
    colConnectors = 'black'
) +
    # ggplot2::coord_flip() +
    theme_slick_no_legend
p_loadings

#TODO Work up some logic for saving the plot


#  Evaluate correlations between PCs and model variables ----------------------
#+ Answer, "What is driving biologically significant variance in our data?"
PC_cor <- PCAtools::eigencorplot(
    obj_pca,
    components = PCAtools::getComponents(obj_pca, 1:length(obj_pca$loadings)),
    # metavars = c("strain", "state", "time", "replicate", "technical"),
    metavars = c("strain", "replicate", "technical"),
    # metavars = c("strain", "replicate", "sample_name"),
    col = c("#785EF075", "#FFFFFF75", "#FE610075"),
    scale = FALSE,
    corFUN = "pearson",
    corMultipleTestCorrection = "BH",
    plotRsquared = TRUE,
    colFrame = "#FFFFFF",
    main = bquote(Pearson ~ r^2 ~ correlates),
    # main = "PC Pearson r-squared correlates",
    fontMain = 1,
    titleX = "Principal components",
    fontTitleX = 1,
    fontLabX = 1,
    titleY = "Model variables",
    rotTitleY = 90,
    fontTitleY = 1,
    fontLabY = 1
)
Warning: strain is not numeric - please check the source data as non-numeric variables will be coerced to numericWarning: replicate is not numeric - please check the source data as non-numeric variables will be coerced to numericWarning: technical is not numeric - please check the source data as non-numeric variables will be coerced to numeric
PC_cor



#  Get lists of top loadings for GO analyses ----------------------------------
# for(i in c("PC1", "PC2", "PC3", "PC4")) {
for(i in c("PC1", "PC2")) {
    #TODO Write results to list so that I only need to query a single object
    # i <- "PC1"
    #  Positive
    loadings_pos_PC <- rownames(top_loadings_pos[[i]])[1:500]
    save_title_pos_PC <- paste0(
        "top-500.",
        stringr::str_replace_all(get_name_of_var(loadings_pos_PC), "_", "-"),
        ".", i, ".txt"
    )
    # readr::write_tsv(
    #     dplyr::as_tibble(loadings_pos_PC),
    #     paste0(args$directory_out, "/", save_title_pos_PC),
    #     col_names = FALSE
    # )
    #TODO Work up some logic for location(s) for outfiles
    
    #  Negative
    loadings_neg_PC <- rownames(top_loadings_neg[[i]])[1:500]
    save_title_neg_PC <- paste0(
        "top-500.",
        stringr::str_replace_all(get_name_of_var(loadings_neg_PC), "_", "-"),
        ".", i, ".txt"
    )
    # readr::write_tsv(
    #     dplyr::as_tibble(loadings_neg_PC),
    #     paste0(args$directory_out, "/", save_title_neg_PC),
    #     col_names = FALSE
    # )
    #TODO Work up some logic for location(s) for outfiles
}



#HERE ## II. Run pairwise analyses


res$datasets_r1_r6$n06d_MA_SC
res$datasets_WT_r6$n06d_MA_SC

res$datasets_WT_r1$n06d_MA_SC


res$datasets_r1_r6$n07d_MA_KL

res$datasets_WT_r6$n07d_MA_KL

res$datasets_WT_r1$n07d_MA_KL


res$datasets_r1_r6$n08d_MA_SC.ctrl_KL

res$datasets_WT_r6$n08d_MA_SC.ctrl_KL

res$datasets_WT_r1$n08d_MA_SC.ctrl_KL


res$datasets_r1_r6$n06e_volcano_SC

res$datasets_WT_r6$n06e_volcano_SC

res$datasets_WT_r1$n06e_volcano_SC


res$datasets_r1_r6$n07e_volcano_KL

res$datasets_WT_r6$n07e_volcano_KL

res$datasets_WT_r1$n07e_volcano_KL


res$datasets_r1_r6$n08e_volcano_SC.ctrl_KL

res$datasets_WT_r6$n08e_volcano_SC.ctrl_KL

res$datasets_WT_r1$n08e_volcano_SC.ctrl_KL


LS0tCnRpdGxlOiAid29ya19ldmFsdWF0aW9uLWV0Y19yb3VnaC1kcmFmdF9ScnA2LVJ0cjEtV1RfU1NfUV9ncm91cHdpc2VfcGFpcndpc2UiCmF1dGhvcjogIktBIgplbWFpbDogImthbGF2YXR0QGZyZWRodXRjaC5vcmciCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KPGJyIC8+CgojIyBQcmVwYXJlIGRhdGEgZm9yIHZhcmlvdXMgREdFIGFuYWx5c2VzCiMjIyBHZXQgc2l0dWF0ZWQKIyMjIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKYGBge3IgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShERVNlcTIpCmxpYnJhcnkoZWRnZVIpCmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQpsaWJyYXJ5KEdlbm9taWNSYW5nZXMpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShJUmFuZ2VzKQpsaWJyYXJ5KFBDQXRvb2xzKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAo8YnIgLz4KCiMjIyMgU2V0IHdvcmtpbmcgZGlyZWN0b3J5CmBgYHtyIFNldCB3b3JraW5nIGRpcmVjdG9yeSwgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0V9CiMgcF9sb2NhbCA8LSAiL1VzZXJzL2thbGF2YXR0YW0vRHJvcGJveC9GSENDIiAgIyBLcmlzTWFjCnBfbG9jYWwgPC0gIi9Vc2Vycy9rYWxhdmF0dC9wcm9qZWN0cy1ldGMiICAjIFdvcmtNYWMKcF93ZCA8LSAiMjAyMl90cmFuc2NyaXB0b21lLWNvbnN0cnVjdGlvbi9yZXN1bHRzLzIwMjMtMDIxNSIKI05PVEUgMS8zIEFsaXNvbjogeW91IGNhbiBhZGp1c3QgJ3BfbG9jYWwnIG9yICdwX3dkJyAocGF0aCB0byB3b3JraW5nIGRpcmVjdG9yeSAKI05PVEUgMi8zIG9uIHlvdXIgcGVyc29uYWwgb3Igd29yayBjb21wdXRlciApOyBJIGhhdmUgdHdvIHBhdGhzIGhlcmUgd2l0aCBvbmUKI05PVEUgMy8zIGNvbW1lbnRlZCBvdXQgZGVwZW5kaW5nIG9uIHdoaWNoIGNvbXB1dGVyIEkgYW0gdXNpbmcKCnNldHdkKHBhc3RlKHBfbG9jYWwsIHBfd2QsIHNlcCA9ICIvIikpCmdldHdkKCkKCnJtKHBfbG9jYWwsIHBfd2QpCmBgYAo8YnIgLz4KCiMjIyMgU2V0IG9wdGlvbnMKLSBVc2Ugbm9ybWFsIG51bWJlcnMgaW5zdGVhZCBvZiBkZWZhdWx0IHNjaWVudGlmaWMgbnVtYmVycyBpbiBwbG90cwotIERvIG5vdCBsaW1pdCBudW1iZXIgb2Ygb3ZlcmxhcHMgd2hlbiBpbmNsdWRpbmcgbGFiZWxzIGluIHBsb3RzCmBgYHtyIFNldCBvcHRpb25zLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kb3B0aW9ucyhzY2lwZW49OTk5KQpvcHRpb25zKGdncmVwZWwubWF4Lm92ZXJsYXBzID0gSW5mKQpgYGAKPGJyIC8+CgojIyMjIEluaXRpYWxpemUgbmVjZXNzYXJ5IGZ1bmN0aW9ucwpgYGB7ciBJbml0aWFsaXplIG5lY2Vzc2FyeSBmdW5jdGlvbnMsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQpzcGxpdF9pc29sYXRlX2NvbnZlcnQgPC0gZnVuY3Rpb24oaW5fdmVjdG9yLCBmaWVsZCwgY29sdW1uX25hbWUpIHsKICAgICMgVGFrZSBpbiBhIGNoYXJhY3RlciB2ZWN0b3Igb2YgUzI4OEMgUjY0LTEtMSBmZWF0dXJlIG5hbWVzIGFuZCBzcGxpdAogICAgIyBlbGVtZW50cyBhdCB0aGUgdW5kZXJzY29yZXMgdGhhdCBzZXBhcmF0ZSBmZWF0dXJlIG5hbWVzIGZyb20KICAgICMgY2xhc3NpZmljYXRpb25zLCBlLmcuLCAiWUVSMDQzX21STkEtRTEiIGlzIHNwbGl0IGF0IHRoZSB1bmRlcnNjb3JlLiBVc2VyCiAgICAjIGhhcyB0aGUgb3B0aW9uIHRvIHJldHVybiBlaXRoZXIgdGhlIGZpcnN0IChmZWF0dXJlIG5hbWUpIG9yIHNlY29uZAogICAgIyAoY2xhc3NpZmljYXRpb24pIHZhbHVlIGluIGEgdGliYmxlIGRhdGEgdHlwZS4gVXNlciBtdXN0IGFsc28gaW5wdXQgYQogICAgIyBuYW1lIGZvciB0aGUgY29sdW1uIGluIHRoZSB0aWJibGUuCiAgICAjCiAgICAjIDpwYXJhbSBpbl92ZWN0b3I6IGNoYXJhY3RlciB2ZWN0b3Igb2YgUzI4OEMgUjY0LTEtMSBmZWF0dXJlIG5hbWVzIFt2ZWNdCiAgICAjIDpwYXJhbSBmaWVsZDogZmlyc3Qgb3Igc2Vjb25kIHN0cmluZyBzZXBhcmF0ZWQgYnkgdW5kZXJzY29yZQogICAgIyAgICAgICAgICAgICAgIFtpbnQgPSAxIHwgaW50ID0gMl0KICAgICMgOnBhcmFtIGNvbHVtbl9uYW1lOiBuYW1lIG9mIGNvbHVtbiBpbiB0aWJibGUgW2Nocl0KICAgICMgOnJldHVybiBvdXRfZGY6IHRpYmJsZSBvZiBmaXJzdCBvciBzZWNvbmQgc3RyaW5ncyBzZXBhcmF0ZWQgYnkgdW5kZXJzY29yZQogICAgIyAgICAgICAgICAgICAgICAgW3RibF0KICAgIG91dF9kZiA8LSBpbl92ZWN0b3IgJT4lCiAgICAgICAgc3RyaW5ncjo6c3RyX3NwbGl0KC4sIGMoIl8iKSkgJT4lCiAgICAgICAgc2FwcGx5KC4sICJbIiwgZmllbGQpICU+JQogICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgICAgICB0aWJibGU6OmFzX3RpYmJsZSgpCiAgICAKICAgIGNvbG5hbWVzKG91dF9kZikgPC0gY29sdW1uX25hbWUKICAgIAogICAgcmV0dXJuKG91dF9kZikKfQojVE9ETyBBZGQgcmV0dXJuIGRlc2NyaXB0aW9uCgoKcGxvdF92b2xjYW5vIDwtIGZ1bmN0aW9uKAogICAgdGFibGUsIGxhYmVsLCBzZWxlY3Rpb24sIGxhYmVsX3NpemUsIHBfY3V0b2ZmLCBGQ19jdXRvZmYsCiAgICB4bGltLCB5bGltLCBjb2xvciwgdGl0bGUsIHN1YnRpdGxlLCAuLi4KKSB7CiAgICAjVE9ETyBXcml0ZSBhIGRlc2NyaXB0aW9uIG9mIHRoaXMgZnVuY3Rpb24KICAgICMKICAgICMgOnBhcmFtIHRhYmxlOiBkYXRhZnJhbWUgb2YgdGVzdCBzdGF0aXN0aWNzIFtkZl0KICAgICMgOnBhcmFtIGxhYmVsOiBjaGFyYWN0ZXIgdmVjdG9yIG9mIGFsbCB2YXJpYWJsZSBuYW1lcyBpbiBwYXJhbSB0YWJsZSBbdmVjXQogICAgIyA6cGFyYW0gc2VsZWN0aW9uOiBjaGFyYWN0ZXIgdmVjdG9yIG9mIHNlbGVjdGVkIHZhcmlhYmxlIG5hbWVzIGluIHBhcmFtCiAgICAjICAgICAgICAgICAgICAgICAgIHRhYmxlIFt2ZWNdCiAgICAjIDpwYXJhbSBsYWJlbF9zaXplOiBzaXplIG9mIGxhYmVsIGZvbnQgW2Zsb2F0XQogICAgIyA6cGFyYW0gcF9jdXRvZmY6IGN1dC1vZmYgZm9yIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZTsgYSBob3Jpem9udGFsIGxpbmUKICAgICMgICAgICAgICAgICAgICAgICB3aWxsIGJlIGRyYXduIGF0IC1sb2cxMChwQ3V0b2ZmKTsgcCBpcyBhY3R1YWxseSBwYWRqCiAgICAjICAgICAgICAgICAgICAgICAgW2Zsb2F0XQogICAgIyA6cGFyYW0gRkNfY3V0b2ZmOiBjdXQtb2ZmIGZvciBhYnNvbHV0ZSBsb2cyIGZvbGQtY2hhbmdlOyB2ZXJ0aWNhbCBsaW5lcwogICAgIyAgICAgICAgICAgICAgICAgICB3aWxsIGJlIGRyYXduIGF0IHRoZSBuZWdhdGl2ZSBhbmQgcG9zaXRpdmUgdmFsdWVzIG9mCiAgICAjICAgICAgICAgICAgICAgICAgIGxvZzJGQ2N1dG9mZgogICAgIyAgICAgICAgICAgICAgICAgIFtmbG9hdF0KICAgICMgOnBhcmFtIHhsaW06IGxpbWl0cyBvZiB0aGUgeC1heGlzIFtmbG9hdF0KICAgICMgOnBhcmFtIHlsaW06IGxpbWl0cyBvZiB0aGUgeS1heGlzIFtmbG9hdF0KICAgICMgOnBhcmFtIGNvbG9yOiBjb2xvciBvZiBERUdzLCBlLmcuLCAnIzUyQkU5QicgW2hleF0KICAgICMgOnBhcmFtIHRpdGxlOiBwbG90IHRpdGxlIFtjaHJdCiAgICAjIDpwYXJhbSBzdWJ0aXRsZTogcGxvdCBzdWJ0aXRsZSBbY2hyXQogICAgIyA6cmV0dXJuIHZvbGNhbm86IC4uLgogICAgdm9sY2FubyA8LSBFbmhhbmNlZFZvbGNhbm86OkVuaGFuY2VkVm9sY2FubygKICAgICAgICB0b3B0YWJsZSA9IHRhYmxlLAogICAgICAgIGxhYiA9IGxhYmVsLAogICAgICAgIHNlbGVjdExhYiA9IHNlbGVjdGlvbiwKICAgICAgICB4ID0gImxvZzJGb2xkQ2hhbmdlIiwKICAgICAgICB5ID0gInBhZGoiLAogICAgICAgIHhsYWIgPSAibG9nMihGQykiLAogICAgICAgIHlsYWIgPSAiLWxvZzEwKHBhZGopIiwKICAgICAgICBwQ3V0b2ZmID0gcF9jdXRvZmYsCiAgICAgICAgcEN1dG9mZkNvbCA9ICJwYWRqIiwKICAgICAgICBGQ2N1dG9mZiA9IEZDX2N1dG9mZiwKICAgICAgICB4bGltID0geGxpbSwKICAgICAgICB5bGltID0geWxpbSwKICAgICAgICBjdXRvZmZMaW5lVHlwZSA9ICJkYXNoZWQiLAogICAgICAgIGN1dG9mZkxpbmVXaWR0aCA9IDAuMiwKICAgICAgICBwb2ludFNpemUgPSAxLAogICAgICAgIHNoYXBlID0gMTYsCiAgICAgICAgY29sQWxwaGEgPSAwLjI1LAogICAgICAgIGNvbCA9IGMoJyNEM0QzRDMnLCAnI0QzRDNEMycsICcjRDNEM0QzJywgY29sb3IpLAogICAgICAgIHRpdGxlID0gTlVMTCwKICAgICAgICBzdWJ0aXRsZSA9IE5VTEwsCiAgICAgICAgY2FwdGlvbiA9IE5VTEwsCiAgICAgICAgYm9yZGVyQ29sb3VyID0gIiMwMDAwMDAiLAogICAgICAgIGJvcmRlcldpZHRoID0gMC4yLAogICAgICAgIGdyaWRsaW5lcy5tYWpvciA9IFRSVUUsCiAgICAgICAgZ3JpZGxpbmVzLm1pbm9yID0gVFJVRSwKICAgICAgICBheGlzTGFiU2l6ZSA9IDEwLAogICAgICAgIGxhYlNpemUgPSBsYWJlbF9zaXplLAogICAgICAgIGJveGVkTGFiZWxzID0gVFJVRSwKICAgICAgICBwYXJzZUxhYmVscyA9IFRSVUUsCiAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgIHdpZHRoQ29ubmVjdG9ycyA9IDAuMiwKICAgICAgICBjb2xDb25uZWN0b3JzID0gJ2JsYWNrJywKICAgICAgICBtYXgub3ZlcmxhcHMgPSBJbmYKICAgICkgKwogICAgICAgIHRoZW1lX3NsaWNrX25vX2xlZ2VuZCArCiAgICAgICAgZ2dwbG90Mjo6Z2d0aXRsZSh0aXRsZSwgc3VidGl0bGUgPSBzdWJ0aXRsZSkKICAgIHJldHVybih2b2xjYW5vKQp9CiNUT0RPIEFkZCByZXR1cm4gZGVzY3JpcHRpb24KCgpzYXZlX3ZvbGNhbm8gPC0gZnVuY3Rpb24ocGxvdCwgZmlsZSwgd2lkdGgsIGhlaWdodCkgewogICAgI1RPRE8gV3JpdGUgYSBkZXNjcmlwdGlvbiBvZiB0aGlzIGZ1bmN0aW9uCiAgICAjCiAgICAjIDpwYXJhbSBwbG90OiAuLi4KICAgICMgOnBhcmFtIGZpbGU6IC4uLgogICAgIyA6cGFyYW0gd2lkdGg6IC4uLgogICAgIyA6cGFyYW0gaGVpZ2h0OiAuLi4KICAgICMgOnJldHVybjogLi4uCiAgICBnZ3Bsb3QyOjpnZ3NhdmUoCiAgICAgICAgcGxvdCwKICAgICAgICBmaWxlbmFtZSA9IGZpbGUsCiAgICAgICAgZGV2aWNlID0gInBkZiIsCiAgICAgICAgaCA9IHdpZHRoLAogICAgICAgIHcgPSBoZWlnaHQsCiAgICAgICAgdW5pdHMgPSAiaW4iCiAgICApCn0KI1RPRE8gQWRkIHJldHVybiBkZXNjcmlwdGlvbgoKCmdldF9uYW1lX29mX3ZhciA8LSBmdW5jdGlvbih2KSB7CiAgICAjVE9ETyBXcml0ZSBhIGRlc2NyaXB0aW9uIG9mIHRoaXMgZnVuY3Rpb24KICAgICMKICAgICMgOnBhcmFtIHY6IC4uLgogICAgIyA6cmV0dXJuIHY6IC4uLgogICAgcmV0dXJuKGRlcGFyc2Uoc3Vic3RpdHV0ZSh2KSkpCn0KI1RPRE8gQWRkIHJldHVybiBkZXNjcmlwdGlvbgoKCmdldF90b3BfbG9hZGluZ3MgPC0gZnVuY3Rpb24oeCwgeSwgeiwgYSkgewogICAgI1RPRE8gV3JpdGUgYSBkZXNjcmlwdGlvbiBvZiB0aGlzIGZ1bmN0aW9uCiAgICAjCiAgICAjIDpwYXJhbSB4OiBkYXRhZnJhbWUgb2YgUEMgbG9hZGluZ3MgPGRhdGEuZnJhbWU+CiAgICAjIDpwYXJhbSB5OiBjaGFyYWN0ZXIgZWxlbWVudCBmb3IgY29sdW1uIGluIGRhdGFmcmFtZSB4IDxjaHI+CiAgICAjIDpwYXJhbSB6OiB3aGV0aGVyIHRvIHNlbGVjdCBhbGwgbG9hZGluZ3Mgc29ydGVkIGZyb20gbGFyZ2VzdCB0byBzbWFsbGVzdAogICAgIyAgICAgICAgICAgYWJzb2x1dGUgdmFsdWUgKCdhbGwnKSwgcG9zaXRpdmUgbG9hZGluZ3Mgc29ydGVkIGZyb20gbGFyZ2VzdAogICAgIyAgICAgICAgICAgdG8gc21hbGxlc3QgdmFsdWUgKCdwb3MnKSwgb3IgbmVnYXRpdmUgbG9hZGluZ3Mgc29ydGVkIGZyb20KICAgICMgICAgICAgICAgIGxhcmdlc3QgdG8gc21hbGxlc3QgYWJzb2x1dGUgdmFsdWUgKCduZWcnKSA8c3RyPgogICAgIyA6cGFyYW0gYTogd2hldGhlciBvciBub3QgdG8ga2VlcCAnc2lnbicgYW5kICdhYnMnIGNvbHVtbnMgYWRkZWQgaW4gdGhlCiAgICAjICAgICAgICAgICBjb3Vyc2Ugb2YgcHJvY2Vzc2luZyB0aGUgZGF0YWZyYW1lIDxsb2dpY2FsPgogICAgIyA6cmV0dXJuIGI6IC4uLgogICAgYiA8LSBhcy5kYXRhLmZyYW1lKHhbW3ldXSkKICAgIHJvd25hbWVzKGIpIDwtIHJvd25hbWVzKHgpCiAgICBjb2xuYW1lcyhiKSA8LSB5CiAgICAKICAgIGJbWyJzaWduIl1dIDwtIGlmZWxzZSgKICAgICAgICBiW1t5XV0gPiAwLAogICAgICAgICJwb3MiLAogICAgICAgIGlmZWxzZSgKICAgICAgICAgICAgYltbeV1dID09IDAsCiAgICAgICAgICAgICJ6ZXJvIiwKICAgICAgICAgICAgIm5lZyIKICAgICAgICApCiAgICApCiAgICAKICAgIGJbWyJhYnMiXV0gPC0gYWJzKGJbW3ldXSkKICAgIAogICAgaWYoeiA9PSAiYWxsIikgewogICAgICAgIGIgPC0gZHBseXI6OmFycmFuZ2UoYiwgYnkgPSBkZXNjKGFicykpCiAgICB9IGVsc2UgaWYoeiA9PSAicG9zIikgewogICAgICAgIGIgPC0gYltiW1t5XV0gPiAwLCBdICU+JSBkcGx5cjo6YXJyYW5nZSguLCBieSA9IGRlc2MoYWJzKSkKICAgIH0gZWxzZSBpZih6ID09ICJuZWciKSB7CiAgICAgICAgYiA8LSBiW2JbW3ldXSA8IDAsIF0gJT4lIGRwbHlyOjphcnJhbmdlKC4sIGJ5ID0gZGVzYyhhYnMpKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKHBhc3RlMCgiU3RvcHBpbmc6IHBhcmFtIHogbXVzdCBiZSBlaXRoZXIgJ2FsbCcsICdwb3MnLCBvciAnbmVnJyIpKQogICAgfQogICAgCiAgICBpZihpc1RSVUUoYSkpIHsKICAgICAgICBwYXN0ZTAoIlJldGFpbmluZyAnc2lnbicgYW5kICdhYnMnIGNvbHVtbnMiKQogICAgfSBlbHNlIGlmKGlzRkFMU0UoYSkpIHsKICAgICAgICBiIDwtIGIgJT4lIGRwbHlyOjpzZWxlY3QoLWMoc2lnbiwgYWJzKSkKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcChwYXN0ZTAoIlN0b3BwaW5nOiBwYXJhbSBhIG11c3QgYmUgZWl0aGVyICdUUlVFJyBvciAnRkFMU0UnIikpCiAgICB9CiAgICAKICAgIHJldHVybihiKQp9CiNUT0RPIEFkZCByZXR1cm4gZGVzY3JpcHRpb24KCgpwbG90X2JpcGxvdCA8LSBmdW5jdGlvbigKICAgIHBjYSwgUENfeCwgUENfeSwKICAgIGxvYWRpbmdzX3Nob3csIGxvYWRpbmdzX24sCiAgICBtZXRhX2NvbG9yLCBtZXRhX3NoYXBlLAogICAgeF9taW4sIHhfbWF4LCB5X21pbiwgeV9tYXgKKSB7CiAgICAjVE9ETyBXcml0ZSBhIGRlc2NyaXB0aW9uIG9mIHRoaXMgZnVuY3Rpb24KICAgICMKICAgICMgOnBhcmFtIHBjYTogInBjYSIgbGlzdCBvYmplY3Qgb2J0YWluZWQgYnkgcnVubmluZyBQQ0F0b29sczo6cGNhKCkKICAgICMgOnBhcmFtIFBDX3g6IFBDIHRvIHBsb3Qgb24gdGhlIHggYXhpcyA8Y2hyPgogICAgIyA6cGFyYW0gUENfeTogUEMgdG8gcGxvdCBvbiB0aGUgeSBheGlzIDxjaHI+CiAgICAjIDpwYXJhbSBsb2FkaW5nc19zaG93OiB3aGV0aGVyIHRvIG92ZXJsYXkgY29tcG9uZW50IGxvYWRpbmdzIG9yIG5vdCA8bGdsPgogICAgIyA6cGFyYW0gbG9hZGluZ3NfbjogbnVtYmVyIG9mIHRvcCBsb2FkaW5ncyB0byBzaG93IDxpbnQgPj0gMD4KICAgICMgOnBhcmFtIG1ldGFfY29sb3I6IGNvbHVtbiBpbiAicGNhIiBsaXN0IG1ldGFkYXRhIHRvIGNvbG9yIGJ5IDxjaHI+CiAgICAjIDpwYXJhbSBtZXRhX3NoYXBlOiBjb2x1bW4gaW4gInBjYSIgbGlzdCBtZXRhZGF0YSB0byBzaGFwZSBieSA8Y2hyPgogICAgIyA6cGFyYW0geF9taW46IG1pbmltdW0gdmFsdWUgb24geCBheGlzIDxkYmw+CiAgICAjIDpwYXJhbSB4X21heDogbWF4aW11bSB2YWx1ZSBvbiB4IGF4aXMgPGRibD4KICAgICMgOnBhcmFtIHlfbWluOiBtaW5pbXVtIHZhbHVlIG9uIHkgYXhpcyA8ZGJsPgogICAgIyA6cGFyYW0geV9tYXg6IG1heGltdW0gdmFsdWUgb24geSBheGlzIDxkYmw+CiAgICAjIDpwYXJhbSB0aXRsZTogdGl0bGUgb2YgYmlwbG90IDxkYmw+CiAgICAjIDpyZXR1cm4gaW1hZ2U6IC4uLgogICAgaW1hZ2UgPC0gcGNhICU+JSAKICAgICAgICBQQ0F0b29sczo6YmlwbG90KAogICAgICAgICAgICB4ID0gUENfeCwKICAgICAgICAgICAgeSA9IFBDX3ksCiAgICAgICAgICAgIGxhYiA9IE5VTEwsCiAgICAgICAgICAgIHNob3dMb2FkaW5ncyA9IGxvYWRpbmdzX3Nob3csCiAgICAgICAgICAgIG50b3BMb2FkaW5ncyA9IGxvYWRpbmdzX24sCiAgICAgICAgICAgIGJveGVkTG9hZGluZ3NOYW1lcyA9IFRSVUUsCiAgICAgICAgICAgIGNvbGJ5ID0gbWV0YV9jb2xvciwKICAgICAgICAgICAgc2hhcGUgPSBtZXRhX3NoYXBlLAogICAgICAgICAgICBlbmNpcmNsZSA9IEZBTFNFLAogICAgICAgICAgICBlbGxpcHNlID0gRkFMU0UsCiAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IEluZiwKICAgICAgICAgICAgeGxpbSA9IGMoeF9taW4sIHhfbWF4KSwKICAgICAgICAgICAgeWxpbSA9IGMoeV9taW4sIHlfbWF4KQogICAgICAgICkgKwogICAgICAgICAgICB0aGVtZV9zbGljawogICAgCiAgICByZXR1cm4oaW1hZ2UpCn0KI1RPRE8gQWRkIHJldHVybiBkZXNjcmlwdGlvbgoKCnBsb3RfcG9zX25lZ19sb2FkaW5nc19lYWNoX2F4aXMgPC0gZnVuY3Rpb24oCiAgICBkZl9hbGwsIGRmX3BvcywgZGZfbmVnLAogICAgUENfeCwgUENfeSwKICAgIHJvd19zdGFydCwgcm93X2VuZCwKICAgIHhfbWluLCB4X21heCwgeV9taW4sIHlfbWF4LAogICAgeF9udWRnZSwgeV9udWRnZSwgeF9sYWJlbCwgeV9sYWJlbCwKICAgIGNvbF9saW5lX3BvcywgY29sX2xpbmVfbmVnLCBjb2xfc2VnX3BvcywgY29sX3NlZ19uZWcKKSB7CiAgICAjVE9ETyBXcml0ZSBhIGRlc2NyaXB0aW9uIG9mIHRoaXMgZnVuY3Rpb24KICAgICMKICAgICMgOnBhcmFtIGRmX2FsbDogZGF0YWZyYW1lOiBhbGwgbG9hZGluZ3MgKGZyb20sIGUuZy4sIFBDQXRvb2xzKQogICAgIyA6cGFyYW0gZGZfcG9zOiBkYXRhZnJhbWU6IHBvc2l0aXZlIGxvYWRpbmdzIG9yZGVyZWQgbGFyZ2VzdCB0byBzbWFsbGVzdAogICAgIyA6cGFyYW0gZGZfbmVnOiBkYXRhZnJhbWU6IG5lZ2F0aXZlIGxvYWRpbmdzIG9yZGVyZWQgc21hbGxlc3QgdG8gbGFyZ2VzdAogICAgIyA6cGFyYW0gUENfeDogUEMgdG8gcGxvdCBvbiB0aGUgeCBheGlzCiAgICAjIDpwYXJhbSBQQ195OiBQQyB0byBwbG90IG9uIHRoZSB5IGF4aXMKICAgICMgOnBhcmFtIHJvd19zdGFydDogcm93IGZyb20gd2hpY2ggdG8gYmVnaW4gc3Vic2V0dGluZyB0aGUgUENzIG9uIHggYW5kIHkKICAgICMgOnBhcmFtIHJvd19lbmQ6IHJvdyBhdCB3aGljaCB0byBlbmQgc3Vic2V0dGluZyB0aGUgUENzIG9uIHggYW5kIHkKICAgICMgOnBhcmFtIHhfbWluOiBtaW5pbXVtIHZhbHVlIG9uIHggYXhpcyA8ZGJsPgogICAgIyA6cGFyYW0geF9tYXg6IG1heGltdW0gdmFsdWUgb24geCBheGlzIDxkYmw+CiAgICAjIDpwYXJhbSB5X21pbjogbWluaW11bSB2YWx1ZSBvbiB5IGF4aXMgPGRibD4KICAgICMgOnBhcmFtIHlfbWF4OiBtYXhpbXVtIHZhbHVlIG9uIHkgYXhpcyA8ZGJsPgogICAgIyA6cGFyYW0geF9udWRnZTogYW1vdW50IHRvIG51ZGdlIGxhYmVscyBvbiB0aGUgeCBheGlzIDxkYmw+CiAgICAjIDpwYXJhbSB5X251ZGdlOiBhbW91bnQgdG8gbnVkZ2UgbGFiZWxzIG9uIHRoZSB5IGF4aXMgPGRibD4KICAgICMgOnBhcmFtIHhfbGFiZWw6IHggYXhpcyBsYWJlbCA8Y2hyPgogICAgIyA6cGFyYW0geV9sYWJlbDogeSBheGlzIGxhYmVsIDxjaHI+CiAgICAjIDpwYXJhbSBjb2xfbGluZV9wb3M6IGNvbG9yOiBsaW5lcywgYXJyb3dzIGZvciBwb3NpdGl2ZSBsb2FkaW5ncyA8Y2hyPgogICAgIyA6cGFyYW0gY29sX2xpbmVfbmVnOiBjb2xvcjogbGluZXMsIGFycm93cyBmb3IgbmVnYXRpdmUgbG9hZGluZ3MgPGNocj4KICAgICMgOnBhcmFtIGNvbF9zZWdfcG9zOiBjb2xvcjogc2VnbWVudHMgY29ubmVjdGluZyBhcnJvd2hlYWQgYW5kIHRleHQgYnViYmxlCiAgICAjICAgICAgICAgICAgICAgICAgICAgZm9yIHBvc2l0aXZlIGxvYWRpbmdzIDxjaHI+CiAgICAjIDpwYXJhbSBjb2xfc2VnX25lZzogY29sb3I6IHNlZ21lbnRzIGNvbm5lY3RpbmcgYXJyb3doZWFkIGFuZCB0ZXh0IGJ1YmJsZQogICAgIyAgICAgICAgICAgICAgICAgICAgIGZvciBuZWdhdGl2ZSBsb2FkaW5ncyA8Y2hyPgogICAgIyA6cmV0dXJuIGltYWdlOiAuLi4KICAgIGZpbHRlcl9wb3NfMSA8LSByb3duYW1lcyhkZl9wb3NbW1BDX3hdXVtyb3dfc3RhcnQ6cm93X2VuZCwgXSkKICAgIGZpbHRlcl9wb3NfMiA8LSByb3duYW1lcyhkZl9wb3NbW1BDX3ldXVtyb3dfc3RhcnQ6cm93X2VuZCwgXSkKICAgIGZpbHRlcl9uZWdfMSA8LSByb3duYW1lcyhkZl9uZWdbW1BDX3hdXVtyb3dfc3RhcnQ6cm93X2VuZCwgXSkKICAgIGZpbHRlcl9uZWdfMiA8LSByb3duYW1lcyhkZl9uZWdbW1BDX3ldXVtyb3dfc3RhcnQ6cm93X2VuZCwgXSkKICAgIAogICAgbG9hZGluZ3NfZmlsdGVyX3Bvc18xIDwtIGRmX2FsbFtyb3duYW1lcyhkZl9hbGwpICVpbiUgZmlsdGVyX3Bvc18xLCBdCiAgICBsb2FkaW5nc19maWx0ZXJfcG9zXzIgPC0gZGZfYWxsW3Jvd25hbWVzKGRmX2FsbCkgJWluJSBmaWx0ZXJfcG9zXzIsIF0KICAgIGxvYWRpbmdzX2ZpbHRlcl9uZWdfMSA8LSBkZl9hbGxbcm93bmFtZXMoZGZfYWxsKSAlaW4lIGZpbHRlcl9uZWdfMSwgXQogICAgbG9hZGluZ3NfZmlsdGVyX25lZ18yIDwtIGRmX2FsbFtyb3duYW1lcyhkZl9hbGwpICVpbiUgZmlsdGVyX25lZ18yLCBdCiAgICAKICAgIGltYWdlcyA8LSBsaXN0KCkKICAgIGltYWdlc1tbIlBDX3hfcG9zIl1dIDwtIHBsb3RfbG9hZGluZ3MoCiAgICAgICAgbG9hZGluZ3NfZmlsdGVyX3Bvc18xLAogICAgICAgIGxvYWRpbmdzX2ZpbHRlcl9wb3NfMVtbUENfeF1dLAogICAgICAgIGxvYWRpbmdzX2ZpbHRlcl9wb3NfMVtbUENfeV1dLAogICAgICAgIHhfbWluLCB4X21heCwgeV9taW4sIHlfbWF4LCB4X251ZGdlLCB5X251ZGdlLAogICAgICAgIHhfbGFiZWwsIHlfbGFiZWwsIGNvbF9saW5lX3BvcywgY29sX3NlZ19wb3MKICAgICkKICAgIGltYWdlc1tbIlBDX3lfcG9zIl1dIDwtIHBsb3RfbG9hZGluZ3MoCiAgICAgICAgbG9hZGluZ3NfZmlsdGVyX3Bvc18yLAogICAgICAgIGxvYWRpbmdzX2ZpbHRlcl9wb3NfMltbUENfeF1dLAogICAgICAgIGxvYWRpbmdzX2ZpbHRlcl9wb3NfMltbUENfeV1dLAogICAgICAgIHhfbWluLCB4X21heCwgeV9taW4sIHlfbWF4LCB4X251ZGdlLCB5X251ZGdlLAogICAgICAgIHhfbGFiZWwsIHlfbGFiZWwsIGNvbF9saW5lX3BvcywgY29sX3NlZ19wb3MKICAgICkKICAgIGltYWdlc1tbIlBDX3hfbmVnIl1dIDwtIHBsb3RfbG9hZGluZ3MoCiAgICAgICAgbG9hZGluZ3NfZmlsdGVyX25lZ18xLAogICAgICAgIGxvYWRpbmdzX2ZpbHRlcl9uZWdfMVtbUENfeF1dLAogICAgICAgIGxvYWRpbmdzX2ZpbHRlcl9uZWdfMVtbUENfeV1dLAogICAgICAgIHhfbWluLCB4X21heCwgeV9taW4sIHlfbWF4LCAteV9udWRnZSwgeF9udWRnZSwKICAgICAgICB4X2xhYmVsLCB5X2xhYmVsLCBjb2xfbGluZV9uZWcsIGNvbF9zZWdfbmVnCiAgICApCiAgICBpbWFnZXNbWyJQQ195X25lZyJdXSA8LSBwbG90X2xvYWRpbmdzKAogICAgICAgIGxvYWRpbmdzX2ZpbHRlcl9uZWdfMiwKICAgICAgICBsb2FkaW5nc19maWx0ZXJfbmVnXzJbW1BDX3hdXSwKICAgICAgICBsb2FkaW5nc19maWx0ZXJfbmVnXzJbW1BDX3ldXSwKICAgICAgICB4X21pbiwgeF9tYXgsIHlfbWluLCB5X21heCwgeF9udWRnZSwgLXlfbnVkZ2UsCiAgICAgICAgeF9sYWJlbCwgeV9sYWJlbCwgY29sX2xpbmVfbmVnLCBjb2xfc2VnX25lZwogICAgKQogICAgcmV0dXJuKGltYWdlcykKfQojVE9ETyBBZGQgcmV0dXJuIGRlc2NyaXB0aW9uCgoKcGxvdF9sb2FkaW5ncyA8LSBmdW5jdGlvbih4LCB5LCB6LCBhLCBiLCBkLCBlLCBmLCBnLCBoLCBpLCBqLCBrKSB7CiAgICAjVE9ETyBXcml0ZSBhIGRlc2NyaXB0aW9uIG9mIHRoaXMgZnVuY3Rpb24KICAgICMKICAgICMgOnBhcmFtIHg6IGRhdGFmcmFtZSBvZiBQQyBsb2FkaW5ncyB3L2dlbmUgbmFtZXMgYXMgcm93bmFtZXMgPGRhdGEuZnJhbWU+CiAgICAjIDpwYXJhbSB5OiBjb2x1bW4gaW4gZGF0YWZyYW1lIHRvIHBsb3Qgb24geCBheGlzIDxkYmw+CiAgICAjIDpwYXJhbSB6OiBjb2x1bW4gaW4gZGF0YWZyYW1lIHRvIHBsb3Qgb24geSBheGlzIDxkYmw+CiAgICAjIDpwYXJhbSBhOiBtaW5pbXVtIHZhbHVlIG9uIHggYXhpcyA8ZGJsPgogICAgIyA6cGFyYW0gYjogbWF4aW11bSB2YWx1ZSBvbiB4IGF4aXMgPGRibD4KICAgICMgOnBhcmFtIGQ6IG1pbmltdW0gdmFsdWUgb24geSBheGlzIDxkYmw+CiAgICAjIDpwYXJhbSBlOiBtYXhpbXVtIHZhbHVlIG9uIHkgYXhpcyA8ZGJsPgogICAgIyA6cGFyYW0gZjogYW1vdW50IHRvIG51ZGdlIGxhYmVscyBvbiB0aGUgeCBheGlzIDxkYmw+CiAgICAjIDpwYXJhbSBnOiBhbW91bnQgdG8gbnVkZ2UgbGFiZWxzIG9uIHRoZSB5IGF4aXMgPGRibD4KICAgICMgOnBhcmFtIGg6IHggYXhpcyBsYWJlbCA8Y2hyPgogICAgIyA6cGFyYW0gaTogeSBheGlzIGxhYmVsIDxjaHI+CiAgICAjIDpwYXJhbSBqOiBjb2xvciBvZiBsaW5lIGFuZCBhcnJvdyA8Y2hyPgogICAgIyA6cGFyYW0gazogY29sb3Igb2Ygc2VnbWVudCBjb25uZWN0aW5nIGFycm93aGVhZCBhbmQgdGV4dCBidWJibGUgPGNocj4KICAgICMgOnJldHVybiBsOiAuLi4KICAgIGwgPC0gZ2dwbG90Mjo6Z2dwbG90KHgsIGdncGxvdDI6OmFlcyh4ID0geSwgeSA9IHopKSArICAjVE9ETyAjRlVOQ1RJT04KICAgICAgICBnZ3Bsb3QyOjpjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoYSwgYiksIHlsaW0gPSBjKGQsIGUpKSArCiAgICAgICAgZ2dwbG90Mjo6Z2VvbV9zZWdtZW50KAogICAgICAgICAgICBhZXMoeGVuZCA9IDAsIHllbmQgPSAwLCBhbHBoYSA9IDAuNSksCiAgICAgICAgICAgIGNvbG9yID0gaiwgCiAgICAgICAgICAgIGFycm93ID0gZ2dwbG90Mjo6YXJyb3coCiAgICAgICAgICAgICAgICBlbmRzID0gImZpcnN0IiwKICAgICAgICAgICAgICAgIHR5cGUgPSAib3BlbiIsCiAgICAgICAgICAgICAgICBsZW5ndGggPSB1bml0KDAuMTI1LCAiaW5jaGVzIikKICAgICAgICAgICAgKQogICAgICAgICkgKwogICAgICAgIGdncmVwZWw6Omdlb21fbGFiZWxfcmVwZWwoCiAgICAgICAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMoCiAgICAgICAgICAgICAgICBmb250ZmFjZSA9IDEsIHNlZ21lbnQuY29sb3IgPSBrLCBzZWdtZW50LnNpemUgPSAwLjI1CiAgICAgICAgICAgICksCiAgICAgICAgICAgIGxhYmVsID0gcm93bmFtZXMoeCksCiAgICAgICAgICAgIGxhYmVsLnNpemUgPSAwLjA1LAogICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsCiAgICAgICAgICAgIG51ZGdlX3ggPSBmLCAgIyAwLjAyCiAgICAgICAgICAgIG51ZGdlX3kgPSBnLCAgIyAwLjA0CiAgICAgICAgICAgIGZvcmNlID0gNCwKICAgICAgICAgICAgZm9yY2VfcHVsbCA9IDEsCiAgICAgICAgICAgIGhqdXN0ID0gMAogICAgICAgICkgKwogICAgICAgIGdncGxvdDI6OnhsYWIoaCkgKwogICAgICAgIGdncGxvdDI6OnlsYWIoaSkgKwogICAgICAgIHRoZW1lX3NsaWNrX25vX2xlZ2VuZAogICAgCiAgICByZXR1cm4obCkKfQojVE9ETyBBZGQgcmV0dXJuIGRlc2NyaXB0aW9uCgoKZHJhd19zY3JlZV9wbG90IDwtIGZ1bmN0aW9uKHBjYSwgaG9ybiwgZWxib3cpIHsKICAgICNUT0RPIFdyaXRlIGEgZGVzY3JpcHRpb24gb2YgdGhpcyBmdW5jdGlvbgogICAgIwogICAgIyA6cGFyYW0gcGNhOiAicGNhIiBsaXN0IG9iamVjdCBvYnRhaW5lZCBieSBydW5uaW5nIFBDQXRvb2xzOjpwY2EoKQogICAgIyA6cGFyYW0gaG9ybjogLi4uCiAgICAjIDpwYXJhbSBlbGJvdzogLi4uCiAgICAjIDpyZXR1cm4gc2NyZWU6IC4uLgogICAgc2NyZWUgPC0gUENBdG9vbHM6OnNjcmVlcGxvdCgKICAgICAgICBwY2EsCiAgICAgICAgY29tcG9uZW50cyA9IFBDQXRvb2xzOjpnZXRDb21wb25lbnRzKHBjYSksCiAgICAgICAgdmxpbmUgPSBjKGhvcm4sIGVsYm93KSwKICAgICAgICB2bGluZVdpZHRoID0gMC4yNSwKICAgICAgICBzaXplQ3VtdWxhdGl2ZVN1bUxpbmUgPSAwLjUsCiAgICAgICAgc2l6ZUN1bXVsYXRpdmVTdW1Qb2ludHMgPSAxLjUKICAgICkgKwogICAgICAgIGdlb21fdGV4dChhZXMoaG9ybiArIDEsIDUwLCBsYWJlbCA9ICJIb3JuJ3MiLCB2anVzdCA9IDIpKSArCiAgICAgICAgZ2VvbV90ZXh0KGFlcyhlbGJvdyArIDEsIDUwLCBsYWJlbCA9ICJFbGJvdyIsIHZqdXN0ID0gLTIpKSArCiAgICAgICAgdGhlbWVfc2xpY2sgKwogICAgICAgIGdncGxvdDI6OnRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgogICAgcmV0dXJuKHNjcmVlKQp9CiNUT0RPIEFkZCByZXR1cm4gZGVzY3JpcHRpb24KCgojICBTZXQgdXAgY3VzdG9tIGdncGxvdDIgcGxvdCB0aGVtZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnRoZW1lX3NsaWNrIDwtIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZSgKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZ2dwbG90Mjo6ZWxlbWVudF9saW5lKGxpbmV3aWR0aCA9IDAuNCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjIpLAogICAgICAgIGF4aXMubGluZSA9IGdncGxvdDI6OmVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjIpLAogICAgICAgIGF4aXMudGlja3MgPSBnZ3Bsb3QyOjplbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC40KSwKICAgICAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoKSwKICAgICAgICBwbG90LnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KCksCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiIikKICAgICkKCnRoZW1lX3NsaWNrX25vX2xlZ2VuZCA8LSB0aGVtZV9zbGljayArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCjxiciAvPgoKCiMjIyBMb2FkIGluIEV4Y2VsIHNwcmVhZHNoZWV0IG9mIHNhbXBsZXMgbmFtZXMgYW5kIHZhcmlhYmxlcwpUaGUgc3ByZWFkc2hlZXQgaW5jbHVkZXMgQWxpc29uJ3Mgb3JpZ2luYWwgc2FtcGxlIG5hbWVzOyB3ZSBjYW4gdXNlIHRoaXMKaW5mb3JtYXRpb24gdG8gYXNzb2NpYXRlIHRoZSBuZXcgc2FtcGxlIG5hbWVzLCB3aGljaCBhcmUgbWFkZSB1cCBvZiBgREVTZXEyYAptb2RlbCB2YXJpYWJsZSB2YWx1ZXMsIHdpdGggdGhlIG9sZCBuYW1lcywgd2hpY2ggcmVmbGVjdCBBbGlzb24ncyB3ZXQtbGFiLApsaWJyYXJ5LXByZXAsIGV0Yy4gd29yawpgYGB7ciBsb2FkIHNwcmVhZHNoZWV0LCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KcF94bCA8LSAibm90ZWJvb2siICAjSU5QQVRICmZfeGwgPC0gInZhcmlhYmxlcy54bHN4IiAgI0lORklMRQp0X3hsIDwtIHJlYWR4bDo6cmVhZF94bHN4KAogICAgcGFzdGUocF94bCwgZl94bCwgc2VwID0gIi8iKSwgc2hlZXQgPSAibWFzdGVyIiwgbmEgPSAiTkEiCikKCnJtKHBfeGwsIGZfeGwpCmBgYAo8YnIgLz4KCiMjIyBMb2FkIGluIGFuZCBwcm9jZXNzIGBmZWF0dXJlQ291bnRzYCB0YWJsZQpgYGB7ciBMb2FkIGluIGFuZCBwcm9jZXNzIGZlYXR1cmVDb3VudHMgdGFibGUsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQojICBMb2FkIGluIGZlYXR1cmVDb3VudHMgdGFibGUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnBfZmMgPC0gIm91dGZpbGVzX2ZlYXR1cmVDb3VudHMvY29tYmluZWRfU0NfS0wvVVRfcHJpbV9VTUkiICAjSU5QQVRICmZfZmMgPC0gIlVUX3ByaW1fVU1JLmZlYXR1cmVDb3VudHMiICAjSU5GSUxFCnRfZmMgPC0gcmVhZC50YWJsZSgKICAgIHBhc3RlKHBfZmMsIGZfZmMsIHNlcCA9ICIvIiksIGhlYWRlciA9IFRSVUUsIHJvdy5uYW1lcyA9IDEKKSAlPiUgCiAgICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigpICU+JQogICAgdGliYmxlOjphc190aWJibGUoKQoKcm0ocF9mYywgZl9mYykKCgojICBDbGVhbiB1cCB0aWJibGUgY29sdW1uIG5hbWVzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmNvbG5hbWVzKHRfZmMpIDwtIGNvbG5hbWVzKHRfZmMpICU+JQogICAgZ3N1Yigicm93bmFtZSIsICJmZWF0dXJlX2luaXQiLCAuKSAlPiUKICAgIGdzdWIoIkNociIsICJjaHIiLCAuKSAlPiUKICAgIGdzdWIoIlN0YXJ0IiwgInN0YXJ0IiwgLikgJT4lCiAgICBnc3ViKCJFbmQiLCAiZW5kIiwgLikgJT4lCiAgICBnc3ViKCJTdHJhbmQiLCAic3RyYW5kIiwgLikgJT4lCiAgICBnc3ViKCJMZW5ndGgiLCAibGVuZ3RoIiwgLikgJT4lCiAgICBnc3ViKCJiYW1zX3JlbmFtZWRcXC5VVF9wcmltX1VNSVxcLiIsICIiLCAuKSAlPiUKICAgIGdzdWIoIlxcLlVUX3ByaW1fVU1JXFwuYmFtIiwgIiIsIC4pICU+JQogICAgZ3N1YigiXFwuZCIsICItZCIsIC4pICU+JQogICAgZ3N1YigiXFwubiIsICItbiIsIC4pICU+JQogICAgZ3N1YigiYXV4XFwuIiwgImF1eC0iLCAuKSAlPiUKICAgIGdzdWIoInRjXFwuIiwgInRjLSIsIC4pCgoKIyAgT3JkZXIgdGliYmxlIGJ5IGNocm9tb3NvbWUgbmFtZXMgYW5kIGZlYXR1cmUgc3RhcnQgcG9zaXRpb25zIC0tLS0tLS0tLS0tLS0tLQpjaHJfU0MgPC0gYygKICAgICJJIiwgIklJIiwgIklJSSIsICJJViIsICJWIiwgIlZJIiwgIlZJSSIsICJWSUlJIiwgIklYIiwgIlgiLCAiWEkiLCAiWElJIiwKICAgICJYSUlJIiwgIlhJViIsICJYViIsICJYVkkiLCAiTWl0byIKKQpjaHJfS0wgPC0gYygiQSIsICJCIiwgIkMiLCAiRCIsICJFIiwgIkYiKQpjaHJfb3JkZXIgPC0gYyhjaHJfU0MsIGNocl9LTCkKdF9mYyRjaHIgPC0gdF9mYyRjaHIgJT4lIGFzLmZhY3RvcigpCnRfZmMkY2hyIDwtIG9yZGVyZWQodF9mYyRjaHIsIGxldmVscyA9IGNocl9vcmRlcikKCnRfZmMgPC0gdF9mYyAlPiUgZHBseXI6OmFycmFuZ2UoY2hyLCBzdGFydCkKCgojICBDYXRlZ29yaXplIGNocm9tb3NvbWVzIGJ5IGdlbm9tZSBvZiBvcmlnaW4gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnRfZmMkZ2Vub21lIDwtIGlmZWxzZSgKICAgIHRfZmMkY2hyICVpbiUgY2hyX1NDLAogICAgIlNfY2VyZXZpc2lhZSIsCiAgICBpZmVsc2UoCiAgICAgICAgdF9mYyRjaHIgJWluJSBjaHJfS0wsCiAgICAgICAgIktfbGFjdGlzIiwKICAgICAgICBOQQogICAgKQopICU+JQogICAgYXMuZmFjdG9yKCkKCiMgIE1vdmUgdGhlIG5ldyBjb2x1bW4gImdlbm9tZSIgdG8gYSBiZXR0ZXIgbG9jYXRpb24gaW4gdGhlIHRpYmJsZSAoYmVmb3JlCiMrIGNvbHVtbiAiY2hyIikKdF9mYyA8LSB0X2ZjICU+JSBkcGx5cjo6cmVsb2NhdGUoImdlbm9tZSIsIC5iZWZvcmUgPSAiY2hyIikKCiMgIENoZWNrIG9uIHZhcmlhYmxlL2NvbHVtbiAiZ2Vub21lIgpsZXZlbHModF9mYyRnZW5vbWUpCnRfZmMgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoZ2Vub21lKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUodGFsbHkgPSBsZW5ndGgoZ2Vub21lKSkKIyAgVGhlIGNvZGUgcmV0dXJucy4uLgojIEtfbGFjdGlzID0gNTY1OSwgU19jZXJldmlzaWFlID0gNzUwNwoKcm0oY2hyX0tMLCBjaHJfU0MsIGNocl9vcmRlcikKCgojICBTcGxpdCBhbmQgYmV0dGVyIG9yZ2FuaXplIHZhcmlhYmxlICdmZWF0dXJlX2luaXQnIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgIFNwbGl0ICdmZWF0dXJlX2luaXQnIGludG8gdHdvIGRpc3RpbmN0IGVsZW1lbnRzIChzZXBhcmF0ZWQgYnkgYW4gdW5kZXJzY29yZSkKZWxfMSA8LSBzcGxpdF9pc29sYXRlX2NvbnZlcnQoCiAgICBpbl92ZWN0b3IgPSB0X2ZjJGZlYXR1cmVfaW5pdCwKICAgIGZpZWxkID0gMSwKICAgIGNvbHVtbl9uYW1lID0gImZlYXR1cmUiCikKZWxfMiA8LSBzcGxpdF9pc29sYXRlX2NvbnZlcnQoCiAgICBpbl92ZWN0b3IgPSB0X2ZjJGZlYXR1cmVfaW5pdCwKICAgIGZpZWxkID0gMiwKICAgIGNvbHVtbl9uYW1lID0gInR5cGUiCikKCiMgIEFwcGVuZCBzcGxpdCBpbmZvcm1hdGlvbiB0byB0aWJibGUgJ3RfZmMnCnRfZmMgPC0gZHBseXI6OmJpbmRfY29scyh0X2ZjLCBlbF8xLCBlbF8yKSAlPiUKICAgIGRwbHlyOjpyZWxvY2F0ZShjKCJmZWF0dXJlIiwgInR5cGUiKSwgLmFmdGVyID0gImZlYXR1cmVfaW5pdCIpCgpybShlbF8xLCBlbF8yKQoKIyAgTGltaXQgdGhlIHNwbGl0dGluZy9yZW9yZ2FuaXphdGlvbiB0byBTLiBjZXJldmlzaWFlIGZlYXR1cmVzIG9ubHk7IHRoZSBhYm92ZQojKyBzcGxpdHRpbmcvcmVvcmdhbml6YXRpb24gd29yayBpc24ndCBhcHByb3ByaWF0ZSBmb3IgSy4gbGFjdGlzICdmZWF0dXJlX2luaXQnCiMrIGluZm9ybWF0aW9uIGJlY2F1c2UgdGhlIEsuIGxhY3RpcyBuYW1pbmcvY2xhc3NpZmljYXRpb24gZGlmZmVycyBmcm9tIHRoZSBTLgojKyBjZXJldmlzaWFlIG5hbWluZy9jbGFzc2lmaWNhdGlvbiBzeXN0ZW0pCnRfZmMkZmVhdHVyZSA8LSBpZmVsc2UoCiAgICB0X2ZjJGdlbm9tZSA9PSAiS19sYWN0aXMiLCB0X2ZjJGZlYXR1cmVfaW5pdCwgdF9mYyRmZWF0dXJlCikKdF9mYyR0eXBlIDwtIGlmZWxzZSgKICAgIHRfZmMkZ2Vub21lID09ICJLX2xhY3RpcyIsIE5BLCB0X2ZjJHR5cGUKKQoKIyAgQ3JlYXRlIGxldmVscyBmb3IgUy4gY2VyZXZpc2lhZSAndHlwZScgTkFzIGFuZCBLLiBsYWN0aXMgJ3R5cGUnIE5BcywgdGhlbgojKyBmYWN0b3JpemUgdmFyaWFibGUgJ3R5cGUnOiBlc3NlbnRpYWxseSwgd2UncmUgbWFraW5nIHRoZSBOQXMgaW50byBsZXZlbHMgc28KIysgdGhhdCB3ZSBjYW4gdGFsbHkgdGhlbSAoYXMgYmVsb3cpIGFuZC9vciBwb3RlbnRpYWxseSBzdWJzZXQgdGhlbTsgaG93ZXZlciwKIysgYmVmb3JlIGRvaW5nIHNvLCB3ZSdyZSBkaWZmZXJlbnRpYXRpbmcgdGhlIE5BcyBieSB3aGV0aGVyIHRoZXkgYXJlCiMrIGFzc29jaWF0ZWQgd2l0aCBTLiBjZXJldmlzaWFlIGZlYXR1cmVzIG9yIEsuIGxhY3RpcyBmZWF0dXJlcwp0X2ZjJHR5cGUgPC0gIGlmZWxzZSgKICAgICh0X2ZjJGdlbm9tZSA9PSAiU19jZXJldmlzaWFlIiAmIGlzLm5hKHRfZmMkdHlwZSkpLAogICAgIk5BX1NDIiwKICAgIGlmZWxzZSgKICAgICAgICAodF9mYyRnZW5vbWUgPT0gIktfbGFjdGlzIiAmIGlzLm5hKHRfZmMkdHlwZSkpLAogICAgICAgICJOQV9LTCIsCiAgICAgICAgdF9mYyR0eXBlCiAgICApCikgJT4lCiAgICBhcy5mYWN0b3IoKQoKIyAgRG8gYSBxdWljayBjaGVjayBvZiB0aGUgdGliYmxlICd0X2ZjJyAod2hlcmUgInRfZmMiIHN0YW5kcyBmb3IgInRpYmJsZQojKyBmZWF0dXJlQ291bnRzIikKdF9mYwoKIyAgQ2hlY2sgb24gdGhlIHNwbGl0IGluZm9ybWF0aW9uOiBUaGlzIGNvZGUgdGFsbGllcyB0aGUgbnVtYmVycyBmZWF0dXJlcyBwZXIKIysgY2xhc3NpZmljYXRpb24sIHdoZXJlIGNsYXNzaWZpY2F0aW9ucyBhcmUgdGhpbmdzIGxpa2UgIm1STkEtRTEiLCAidFJOQS1FMSIsCiMrICJOQV9TQyIgKE5BcyBhc3NvY2lhdGVkIHdpdGggUy4gY2VyZXZpc2lhZSksICJOQV9LTCIgKE5BcyBhc3NvY2lhdGVkIHdpdGggSy4KIysgbGFjdGlzKSwgZXRjLgpsZXZlbHModF9mYyR0eXBlKSAgIyAxOSBsZXZlbHMKdF9mYyAlPiUKICAgIGRwbHlyOjpncm91cF9ieSh0eXBlKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUodGFsbHkgPSBsZW5ndGgodHlwZSkpCiMgIFRoZSBjb2RlIHJldHVybnMgdGhpbmdzIGxpa2UuLi4KIysgbVJOQS1FMSA9IDY2MDAsIG1STkEtRTIgPSAyODMsIE5BX0tMID0gNTU0NywgTkFfU0MgPSAxMDMsIHRSTkEtRTEgPSAyOTksCiMrIHRSTkEtRTIgPSA2MCwgZXRjLgpgYGAKPGJyIC8+CgojIyMgUmVjb3JkIHRpYmJsZSBgdF9mY2AncyBwb3NpdGlvbmFsIGluZm9ybWF0aW9uIGluIGEgYEdSYW5nZXNgIG9iamVjdApgcG9zX2luZm9gIHdpbGwgYmUgdXNlZCBpbiBgREVTZXEyYCBwcm9jZXNzaW5nLCBwb3N0LXByb2Nlc3NpbmcsIGV0Yy4KCmBgYHtyIFJlY29yZCBwb3NpdGlvbmFsIGluZm9ybWF0aW9uLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KcG9zX2luZm8gPC0gR2Vub21pY1Jhbmdlczo6R1JhbmdlcygKICAgIHNlcW5hbWVzID0gdF9mYyRjaHIsCiAgICByYW5nZXMgPSBJUmFuZ2VzOjpJUmFuZ2VzKHRfZmMkc3RhcnQsIHRfZmMkZW5kKSwKICAgIHN0cmFuZCA9IHRfZmMkc3RyYW5kLAogICAgbGVuZ3RoID0gdF9mYyRsZW5ndGgsCiAgICBmZWF0dXJlID0gdF9mYyRmZWF0dXJlLAogICAgZmVhdHVyZV9pbml0ID0gdF9mYyRmZWF0dXJlX2luaXQsCiAgICB0eXBlID0gdF9mYyR0eXBlLAogICAgZ2Vub21lID0gdF9mYyRnZW5vbWUKKQpwb3NfaW5mbwpgYGAKPGJyIC8+CjxiciAvPgoKIyMgUGVyZm9ybSBub3JtYWxpemF0aW9uIGFuZCBydW4gREdFIGFuYWx5c2VzCiMjIyBQZXJmb3JtIHByZXAgd29yawojIyMjIEVzdGFibGlzaCB0YWJsZSBvZiB2YXJpYWJsZXMgZm9yIGBkZHNgJm1kYXNoO2kuZS4sIGEgIm1hc3RlciIgbW9kZWwgbWF0cml4Ci0gYGRkc2Agc3RhbmRzIGZvciAqIkRFU2VxMiBkYXRhc2V0IiogYW5kIGlzIGEgYERFU2VxRGF0YVNldGAgb2JqZWN0Ci0gdmFyaWFibGVzIGZvciBgZGRzYCBhcmUKICAgICsgYHN0cmFpbmAKICAgICsgYHN0YXRlYAogICAgKyBgdGltZWAKICAgICsgYGtpdGAgKihgdGNuYCBmb3IgIlRlY2FuIiwgYG92bmAgZm9yICJPdmF0aW9uIikqCiAgICArIGB0cmFuc2NyaXB0aW9uYCAqKGBOYCBmb3IgIm5hc2NlbnQiLCBgU1NgIGZvciAic3RlYWR5IHN0YXRlIikqCiAgICArIGBhdXhpbmAKICAgICsgYHRpbWVjb3Vyc2VgCiAgICArIGByZXBsaWNhdGVgCiAgICArIGB0ZWNobmljYWxgCgpgYGB7ciBNYWtlIGEgbWFzdGVyIG1vZGVsIG1hdHJpeCwgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0V9CiMgIENvbHVtbnMgdGVuIHRocm91Z2ggdG8gdGhlIGxhc3QgY29sdW1uIGFyZSBjb21wb3NlZCBvZiBzYW1wbGUgZmVhdHVyZQojKyBjb3VudHM7IGdldCB0aGVzZSBjb2x1bW4gbmFtZXMgaW50byBhIHZlY3RvcgpzYW1wbGVzIDwtIGNvbG5hbWVzKHRfZmMpWzEwOmxlbmd0aChjb2xuYW1lcyh0X2ZjKSldCgojICBDb252ZXJ0IHRoZSB2ZWN0b3Igb2YgY29sdW1uIG5hbWVzIHRvIGEgbGlzdCBieSBzcGxpdHRpbmcgZWFjaCBlbGVtZW50IGF0CiMrIGl0cyB1bmRlcnNjb3JlczsgdGh1cywgZWFjaCB2ZWN0b3IgZWxlbWVudCBiZWNvbWVzIGEgbGlzdCBvZiBlaWdodCBzdHJpbmdzLAojKyB3aXRoIG9uZSBzdHJpbmcgZm9yICdzdHJhaW4nLCBvbmUgZm9yICdzdGF0ZScsIGV0Yy47IHRoZXNlIApzYW1wbGVzIDwtIHN0cmluZ3I6OnN0cl9zcGxpdChzYW1wbGVzLCAiXyIpCgojICBDb252ZXJ0IHRoZSBsaXN0IHRvIGEgZGF0YWZyYW1lLCB0cmFuc3Bvc2UgaXQsIHRoZW4gY29udmVydCBpdCB0byBhIHRpYmJsZQojKyBbUiBmdW4gZmFjdDogJ3RpYmJsZScgZGF0YSB0eXBlcyBjYW4ndCBiZSBidWlsdCBkaXJlY3RseSBmcm9tICdsaXN0JyBkYXRhCiMrIHR5cGVzOyBpbiBmYWN0LCBpdCBjYW4gZGlmZmljdWx0IHRvIGJ1aWxkICdkYXRhZnJhbWUnIHR5cGVzIGZyb20gJ2xpc3QnCiMrIHR5cGVzIGFzIHdlbGw7IHRoZSByZWFzb24gd2UgaGF2ZSBubyBpc3N1ZXMgZG9pbmcgdGhpcyBpcyBiZWNhdXNlIHdlIGhhdmUKIysgZW5zdXJlZCBhaGVhZCBvZiB0aW1lIHRoYXQgZWFjaCBsaXN0IGVsZW1lbnQgaGFzIHRoZSBzYW1lIG51bWJlciBvZgojKyBzdWJlbGVtZW50cyAoOCk7IHRoZSBkaWZmaWN1bHR5IGFyaXNlcyB3aGVuIGxpc3RzIGVsZW1lbnRzIGhhdmUgdmFyeWluZwojKyBudW1iZXJzIG9mIHN1YmVsZW1lbnRzXQpzYW1wbGVzIDwtIHNhbXBsZXMgJT4lCiAgICBhcy5kYXRhLmZyYW1lKAogICAgICAgIC4sCiAgICAgICAgIyAgVXNpbmcgbnVtZXJpYyBjb2x1bW4gbmFtZXMgaGVyZSBiZWNhdXNlIHRoZSBjb2x1bW5zIHdpbGwgc29vbiBiZQogICAgICAgICMrIHRyYW5zcG9zZWQgdG8gcm93cywgYW5kIEkgZG9uJ3Qgd2FudCB0aGUgcm93cyB0byBoYXZlIHByb3BlciBuYW1lcwogICAgICAgIGNvbC5uYW1lcyA9IGMoc2VxKDEsIDYyKSksCiAgICAgICAgIyAgVXNpbmcgcHJvcGVyIHJvdyBuYW1lcyBoZXJlIGJlY2F1c2UgdGhlIHJvd3Mgd2lsbCBzb29uIGJlIHRyYW5zcG9zZWQKICAgICAgICAjKyB0byBjb2x1bW5zLCBhbmQgSSAqZG8qIHdhbnQgdGhlIGNvbHVtbnMgdG8gaGF2ZSBwcm9wZXIgbmFtZXMgCiAgICAgICAgcm93Lm5hbWVzID0gYygKICAgICAgICAgICAgInN0cmFpbiIsICJzdGF0ZSIsICJ0aW1lIiwgImtpdCIsICJ0cmFuc2NyaXB0aW9uIiwgImF1eGluIiwKICAgICAgICAgICAgInRpbWVjb3Vyc2UiLCAicmVwbGljYXRlIiwgInRlY2huaWNhbCIKICAgICAgICApCiAgICApICU+JQogICAgdCgpICU+JQogICAgdGliYmxlOjphc190aWJibGUoKQoKIyAgQWRkIGEga2V5cyB2YXJpYWJsZSBmb3IgcXVpY2tseSBhY2Nlc3NpbmcgY29tYmluYXRpb25zIG9mIHZhcmlhYmxlIHZhbHVlcwprZXlzIDwtIHZlY3Rvcihtb2RlID0gImNoYXJhY3RlciIpCmZvcihpIGluIHNlcSgxLCBucm93KHNhbXBsZXMpKSkgewogICAgIyBpIDwtIDEKICAgIGtleXNbaV0gPC0gcGFzdGUoCiAgICAgICAgc2FtcGxlc1tpLCAxXSwgc2FtcGxlc1tpLCAyXSwgc2FtcGxlc1tpLCAzXSwKICAgICAgICBzYW1wbGVzW2ksIDRdLCBzYW1wbGVzW2ksIDVdLCBzYW1wbGVzW2ksIDZdLAogICAgICAgIHNhbXBsZXNbaSwgN10sIHNhbXBsZXNbaSwgOF0sIHNhbXBsZXNbaSwgOV0sCiAgICAgICAgc2VwID0gIl8iCiAgICApCn0Ka2V5cyA8LSBrZXlzICU+JSBhcy5kYXRhLmZyYW1lKCkKY29sbmFtZXMoa2V5cykgPC0gImtleXMiCgpzYW1wbGVzIDwtIGRwbHlyOjpiaW5kX2NvbHMoc2FtcGxlcywga2V5cykgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoImtleXMiLCAuYmVmb3JlID0gInN0cmFpbiIpCgpybShpKQoKIyAgQWRkIEFsaXNvbidzIG9yaWdpbmFsIHNhbXBsZXMgbmFtZXMgdG8gdGhlICdzYW1wbGVzJyBkYXRhZnJhbWUgdXNpbmcgdGhlCiMrICd0X3hsJyBkYXRhZnJhbWU7IGhlcmUsIHdlJ3JlIGp1c3QgYWRkaW5nIHRoZSBvcmlnaW5hbCBzYW1wbGUgbmFtZXMsIGJ1dCB3ZQojKyBjb3VsZCBwb3RlbnRpYWxseSBhZGQgaW4gb3RoZXIgaW5mb3JtYXRpb24gc3RvcmVkIGluIHRoZSBFeGNlbCBmaWxlCnRfeGwgPC0gdF94bCAlPiUKICAgIGRwbHlyOjpyZW5hbWUoa2V5cyA9IG5hbWUpICU+JQogICAgZHBseXI6OnNlbGVjdCguLCBjKGtleXMsIHNhbXBsZV9uYW1lKSkKc2FtcGxlcyA8LSBkcGx5cjo6ZnVsbF9qb2luKHNhbXBsZXMsIHRfeGwsIGJ5ID0gImtleXMiKQoKIyAjICBDb252ZXJ0IGFsbCBjb2x1bW5zIHRvIGRhdGEgdHlwZSAnZmFjdG9yJyAoaGF2aW5nIHRoZSB2YXJpYWJsZSB2YWx1ZXMgYXMKIyAjKyBmYWN0b3JzIGhlbHBzIHdpdGggcnVubmluZyBERVNlcTI6OkRFU2VxRGF0YVNldEZyb21NYXRyaXgoKSBiZWxvdykKIyBzYW1wbGVzW3NhcHBseShzYW1wbGVzLCBpcy5jaGFyYWN0ZXIpXSA8LSBsYXBwbHkoCiMgICAgIHNhbXBsZXNbc2FwcGx5KHNhbXBsZXMsIGlzLmNoYXJhY3RlcildLCBhcy5mYWN0b3IKIyApCiNUT0RPIEhvbGQgb2ZmIG9uIGZhY3RvciBjb252ZXJzaW9uL29yZGVyZWQtZmFjdG9yIGNvbnZlcnNpb24KCiMgIEhvdyBkb2VzIGl0IGxvb2s/CnNhbXBsZXMKCnJtKHRfeGwsIGtleXMpCmBgYAo8YnIgLz4KCiMjIyMgQmVnaW4gdG8gYXNzZXNzIGZhY3RvciBlbnVtZXJhdGlvbiAocm91Z2gtZHJhZnQpCmBgYHtyIEJlZ2luIHRvIGFzc2VzcyBmYWN0b3IgZW51bWVyYXRpb24sIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQpjb2xuYW1lcyhzYW1wbGVzKQojIHNhbXBsZXMka2V5cwpzYW1wbGVzJHN0cmFpbiAlPiUgYXMuZmFjdG9yKCkgJT4lIHRhYmxlKCkKc2FtcGxlcyRzdGF0ZSAlPiUgYXMuZmFjdG9yKCkgJT4lIHRhYmxlKCkKc2FtcGxlcyR0aW1lICU+JSBhcy5mYWN0b3IoKSAlPiUgdGFibGUoKQpzYW1wbGVzJGtpdCAlPiUgYXMuZmFjdG9yKCkgJT4lIHRhYmxlKCkKc2FtcGxlcyR0cmFuc2NyaXB0aW9uICU+JSBhcy5mYWN0b3IoKSAlPiUgdGFibGUoKQpzYW1wbGVzJGF1eGluICU+JSBhcy5mYWN0b3IoKSAlPiUgdGFibGUoKQpzYW1wbGVzJHRpbWVjb3Vyc2UgJT4lIGFzLmZhY3RvcigpICU+JSB0YWJsZSgpCnNhbXBsZXMkcmVwbGljYXRlICU+JSBhcy5mYWN0b3IoKSAlPiUgdGFibGUoKQpzYW1wbGVzJHRlY2huaWNhbCAlPiUgYXMuZmFjdG9yKCkgJT4lIHRhYmxlKCkKIyBzYW1wbGVzJHNhbXBsZV9uYW1lICU+JSBhcy5mYWN0b3IoKSAlPiUgdGFibGUoKQpgYGAKPGJyIC8+CjxiciAvPgoKIyMgSWRlbnRpZnkgc3BlY2lmaWMgc2FtcGxlcyB0byBldmFsdWF0ZQpgYGB7YmFzaCBJZGVudGlmeSBzcGVjaWZpYyBzYW1wbGVzLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KIyEvYmluL2Jhc2gKI0RPTlRSVU4KCiMgIEFycmF5IG9mIHNhbXBsZXMgc2VxdWVuY2VkIGluIE1hcmNoLCAyMDIzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0Kc2FtcGxlc19NYXJjaD0oCiAgICAiV1RfRFNwNDhfZGF5NF90Y25fU1NfYXV4LUZfdGMtVF9yZXAxX3RlY2gyIgogICAgInI2LW5fRFNwNDhfZGF5NF90Y25fU1NfYXV4LUZfdGMtVF9yZXAyX3RlY2gxIgogICAgInI2LW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDIiCiAgICAiV1RfRzFfZGF5MV90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIgogICAgIldUX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIKICAgICJyNi1uX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSIKICAgICJyNi1uX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIKKQojIFdUX0RTcDQ4X2RheTRfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMiAgICBCTTEwX0RTcDQ4XzU3ODFfbmV3ICAgIFNTIHRpbWVjb3Vyc2U6IHJycDbiiIYgdnMgV1QKIyByNi1uX0RTcDQ4X2RheTRfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSAgICBCTTEyX0RTcDQ4XzcwNzkgICAgU1MgdGltZWNvdXJzZTogcnJwNuKIhiB2cyBXVAojIHI2LW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDIgICAgQ1c2XzcwNzhfZGF5OF9RX1NTICAgIFEgU1M6IHJycDbiiIYgdnMgcnRyMeKIhiB2cyBXVAojIFdUX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSAgICBEQTFfNTc4MV9TU19HMSAgICBHMSBOOiBycnA24oiGIHZzIFdUCiMgV1RfRzFfZGF5MV90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxICAgIERBMl81NzgyX1NTX0cxICAgIEcxIE46IHJycDbiiIYgdnMgV1QKIyByNi1uX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSAgICBEQTNfNzA3OF9TU19HMSAgICBHMSBOOiBycnA24oiGIHZzIFdUCiMgcjYtbl9HMV9kYXkxX3Rjbl9TU19hdXgtRl90Yy1GX3JlcDJfdGVjaDEgICAgREE0XzcwNzlfU1NfRzEgICAgRzEgTjogcnJwNuKIhiB2cyBXVAoKCiMgIFNTIHRpbWVjb3Vyc2U6IHJycDbiiIYgdnMgV1QgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojKyAtIHdvcmtfZXZhbHVhdGlvbi1ldGNfcm91Z2gtZHJhZnRfUnJwNi1XVF9TU190aW1lY291cnNlX2dyb3Vwd2lzZS5SbWQgICNNQURFCiMrIC0gd29ya19ldmFsdWF0aW9uLWV0Y19yb3VnaC1kcmFmdF9ScnA2LVdUX1NTX3RpbWVjb3Vyc2VfcGFpcndpc2UuUm1kICAjTUFERQpyNl9XVF9TU190Yz0oCiAgICAicjYtbl9EU20yX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMSIKICAgICJyNi1uX0RTbTJfZGF5Ml90Y25fU1NfYXV4LUZfdGMtVF9yZXAyX3RlY2gxIgogICAgInI2LW5fRFNwMl9kYXkyX3Rjbl9TU19hdXgtRl90Yy1UX3JlcDFfdGVjaDEiCiAgICAicjYtbl9EU3AyX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSIKICAgICJyNi1uX0RTcDI0X2RheTNfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMSIKICAgICJyNi1uX0RTcDI0X2RheTNfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSIKICAgICJyNi1uX0RTcDQ4X2RheTRfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMSIKICAgICJyNi1uX0RTcDQ4X2RheTRfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSIKICAgICJXVF9EU20yX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMSIKICAgICJXVF9EU20yX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSIKICAgICJXVF9EU3AyX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMSIKICAgICJXVF9EU3AyX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSIKICAgICJXVF9EU3AyNF9kYXkzX3Rjbl9TU19hdXgtRl90Yy1UX3JlcDFfdGVjaDEiCiAgICAiV1RfRFNwMjRfZGF5M190Y25fU1NfYXV4LUZfdGMtVF9yZXAyX3RlY2gxIgogICAgIldUX0RTcDQ4X2RheTRfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMSIKICAgICJXVF9EU3A0OF9kYXk0X3Rjbl9TU19hdXgtRl90Yy1UX3JlcDFfdGVjaDIiCiAgICAiV1RfRFNwNDhfZGF5NF90Y25fU1NfYXV4LUZfdGMtVF9yZXAyX3RlY2gxIgopCiMgcjYtbl9EU20yX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMSAgICBCcDNfRFNtMl83MDc4CiMgcjYtbl9EU20yX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSAgICBCTTNfRFNtMl83MDc5CiMgcjYtbl9EU3AyX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMV90ZWNoMSAgICBCcDZfRFNwMl83MDc4CiMgcjYtbl9EU3AyX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSAgICBCTTZfRFNwMl83MDc5CiMgcjYtbl9EU3AyNF9kYXkzX3Rjbl9TU19hdXgtRl90Yy1UX3JlcDFfdGVjaDEgICAgQnA5X0RTcDI0XzcwNzgKIyByNi1uX0RTcDI0X2RheTNfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSAgICBCTTlfRFNwMjRfNzA3OQojIHI2LW5fRFNwNDhfZGF5NF90Y25fU1NfYXV4LUZfdGMtVF9yZXAxX3RlY2gxICAgIEJwMTJfRFNwNDhfNzA3OAojIHI2LW5fRFNwNDhfZGF5NF90Y25fU1NfYXV4LUZfdGMtVF9yZXAyX3RlY2gxICAgIEJNMTJfRFNwNDhfNzA3OQojIFdUX0RTbTJfZGF5Ml90Y25fU1NfYXV4LUZfdGMtVF9yZXAxX3RlY2gxICAgIEJNMV9EU20yXzU3ODEKIyBXVF9EU20yX2RheTJfdGNuX1NTX2F1eC1GX3RjLVRfcmVwMl90ZWNoMSAgICBCcDFfRFNtMl81NzgyCiMgV1RfRFNwMl9kYXkyX3Rjbl9TU19hdXgtRl90Yy1UX3JlcDFfdGVjaDEgICAgQk00X0RTcDJfNTc4MQojIFdUX0RTcDJfZGF5Ml90Y25fU1NfYXV4LUZfdGMtVF9yZXAyX3RlY2gxICAgIEJwNF9EU3AyXzU3ODIKIyBXVF9EU3AyNF9kYXkzX3Rjbl9TU19hdXgtRl90Yy1UX3JlcDFfdGVjaDEgICAgQk03X0RTcDI0XzU3ODEKIyBXVF9EU3AyNF9kYXkzX3Rjbl9TU19hdXgtRl90Yy1UX3JlcDJfdGVjaDEgICAgQnA3X0RTcDI0XzU3ODIKIyBXVF9EU3A0OF9kYXk0X3Rjbl9TU19hdXgtRl90Yy1UX3JlcDFfdGVjaDEgICAgQk0xMF9EU3A0OF81NzgxCiMgV1RfRFNwNDhfZGF5NF90Y25fU1NfYXV4LUZfdGMtVF9yZXAxX3RlY2gyICAgIEJNMTBfRFNwNDhfNTc4MV9uZXcKIyBXVF9EU3A0OF9kYXk0X3Rjbl9TU19hdXgtRl90Yy1UX3JlcDJfdGVjaDEgICAgQnAxMF9EU3A0OF81NzgyCgoKIyAgRzEgTjogcnJwNuKIhiB2cyBXVCAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMrIC0gd29ya19ldmFsdWF0aW9uLWV0Y19yb3VnaC1kcmFmdF9ScnA2LVdUX05fRzFfcGFpcndpc2UuUm1kICAjTUFERQpyNl9XVF9HMV9OPSgKICAgICJyNi1uX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSIKICAgICJyNi1uX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIKICAgICJXVF9HMV9kYXkxX3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDEiCiAgICAiV1RfRzFfZGF5MV90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxIgopCiMgcjYtbl9HMV9kYXkxX3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDEgICAgREEzXzcwNzhfU1NfRzEKIyByNi1uX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSAgICBEQTRfNzA3OV9TU19HMQojIFdUX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSAgICBEQTFfNTc4MV9TU19HMQojIFdUX0cxX2RheTFfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSAgICBEQTJfNTc4Ml9TU19HMQoKCiMgIFEgTjogcnJwNuKIhiB2cyBydHIx4oiGIHZzIFdUIChubyBzYW1wbGVzIGZyb20gTWFyY2gsIDIwMjMpIC0tLS0tLS0tLS0tLS0tLS0tLS0tCiMrIC0gd29ya19ldmFsdWF0aW9uLWV0Y19yb3VnaC1kcmFmdF9ScnA2LVJ0cjEtV1RfTl9RX2dyb3Vwd2lzZS5SbWQgICNNQURFCiMrIC0gd29ya19ldmFsdWF0aW9uLWV0Y19yb3VnaC1kcmFmdF9ScnA2LVJ0cjEtV1RfTl9RX3BhaXJ3aXNlLlJtZCAgI01BREUKcjZfcjFfV1RfUV9OPSgKICAgICJyNi1uX1FfZGF5OF90Y25fTl9hdXgtRl90Yy1GX3JlcDFfdGVjaDEiCiAgICAicjYtbl9RX2RheThfdGNuX05fYXV4LUZfdGMtRl9yZXAyX3RlY2gxIgogICAgInIxLW5fUV9kYXk4X3Rjbl9OX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSIKICAgICJyMS1uX1FfZGF5OF90Y25fTl9hdXgtRl90Yy1GX3JlcDJfdGVjaDEiCiAgICAiV1RfUV9kYXk4X3Rjbl9OX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSIKICAgICJXVF9RX2RheThfdGNuX05fYXV4LUZfdGMtRl9yZXAyX3RlY2gxIgopCiMgcjYtbl9RX2RheThfdGNuX05fYXV4LUZfdGMtRl9yZXAxX3RlY2gxICAgIENXNl83MDc4XzhkYXlfUV9QRAojIHI2LW5fUV9kYXk4X3Rjbl9OX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSAgICBDVzhfNzA3OV84ZGF5X1FfUEQKIyByMS1uX1FfZGF5OF90Y25fTl9hdXgtRl90Yy1GX3JlcDFfdGVjaDEgICAgQ1cxMF83NzQ3XzhkYXlfUV9QRAojIHIxLW5fUV9kYXk4X3Rjbl9OX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSAgICBDVzEyXzc3NDhfOGRheV9RX1BECiMgV1RfUV9kYXk4X3Rjbl9OX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSAgICBDVzJfNTc4MV84ZGF5X1FfUEQKIyBXVF9RX2RheThfdGNuX05fYXV4LUZfdGMtRl9yZXAyX3RlY2gxICAgIENXNF81NzgyXzhkYXlfUV9QRAoKCiMgIFEgU1M6IHJycDbiiIYgdnMgcnRyMeKIhiB2cyBXVCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMrIC0gd29ya19ldmFsdWF0aW9uLWV0Y19yb3VnaC1kcmFmdF9ScnA2LVJ0cjEtV1RfU1NfUV9ncm91cHdpc2UuUm1kICAjTUFERQojKyAtIHdvcmtfZXZhbHVhdGlvbi1ldGNfcm91Z2gtZHJhZnRfUnJwNi1SdHIxLVdUX1NTX1FfcGFpcndpc2UuUm1kICAjTUFERQpyNl9yMV9XVF9RX1NTPSgKICAgICJyNi1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIgogICAgInI2LW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDIiCiAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIKICAgICJyMS1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIgogICAgInIxLW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDJfdGVjaDEiCiAgICAiV1RfUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDEiCiAgICAiV1RfUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDJfdGVjaDEiCikKIyByNi1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxICAgIENXNl83MDc4XzhkYXlfUV9JTgojIHI2LW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDIgICAgQ1c2XzcwNzhfZGF5OF9RX1NTCiMgcjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSAgICBDVzhfNzA3OV84ZGF5X1FfSU4KIyByMS1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxICAgIENXMTBfNzc0N184ZGF5X1FfSU4KIyByMS1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxICAgIENXMTJfNzc0OF84ZGF5X1FfSU4KIyBXVF9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSAgICBDVzJfNTc4MV84ZGF5X1FfSU4KIyBXVF9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSAgICBDVzRfNTc4Ml84ZGF5X1FfSU4KCgojICBUZXN0cyBvZiB0aGUgVGVjYW4ga2l0IChubyBzYW1wbGVzIGZyb20gTWFyY2gsIDIwMjMpIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnRlc3RfVGVjYW5fV1Q9KAogICAgIldUX1FfZGF5N190Y25fTl9hdXgtRl90Yy1GX3JlcDJfdGVjaDEiCiAgICAiV1RfUV9kYXk3X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDJfdGVjaDEiCikKIyBXVF9RX2RheTdfdGNuX05fYXV4LUZfdGMtRl9yZXAyX3RlY2gxICAgIENVMTFfNTc4Ml9RX05hc2NlbnQKIyBXVF9RX2RheTdfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSAgICBDVTEyXzU3ODJfUV9TdGVhZHlTdGF0ZQpgYGAKPGJyIC8+CjxiciAvPgoKIyMgRG8gcHJlcCB3b3JrIHdpdGggImBRIFNTOiBycnA24oiGIHZzIHJ0cjHiiIYgdnMgV1RgIgojIyMgRm9yIGBkYXRhc2V0c19hbGxgLCBtYWtlIHRoZSBjb3VudHMgbWF0cml4CmBgYHtyIGRhdGFzZXRfYWxsOiBNYWtlIHRoZSBjb3VudHMgbWF0cml4LCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KZGF0YXNldHNfYWxsIDwtIGMoCiAgICAiV1RfUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDEiLAogICAgIldUX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxIiwKICAgICJyMS1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIiwKICAgICJyMS1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxIiwKICAgICJyNi1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIiwKICAgICJyNi1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gyIiwKICAgICJyNi1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxIgopCiMgZGF0YXNldHNfcjFfcjYgPC0gYygKIyAgICAgInIxLW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDEiLAojICAgICAicjEtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIsCiMgICAgICJyNi1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIiwKIyAgICAgInI2LW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDIiLAojICAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIKIyApCiMgZGF0YXNldHNfV1RfcjYgPC0gYygKIyAgICAgIldUX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIiwKIyAgICAgIldUX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxIiwKIyAgICAgInI2LW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDEiLAojICAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMiIsCiMgICAgICJyNi1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxIgojICkKIyBkYXRhc2V0c19XVF9yMSA8LSBjKAojICAgICAicjEtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSIsCiMgICAgICJyMS1uX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxIiwKIyAgICAgIldUX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIiwKIyAgICAgIldUX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAyX3RlY2gxIgojICkKCiMgIEZvciBub3csIGZvY3VzIG9uIGRhdGFzZXRzX2FsbApkYXRhc2V0cyA8LSBkYXRhc2V0c19hbGwgICNJTVBPUlRBTlQgI0NPTUVCQUNLVE9USElTCmNvdW50c19kYXRhIDwtIHRfZmNbLCBjb2xuYW1lcyh0X2ZjKSAlaW4lIGRhdGFzZXRzXSAlPiUKICAgIGFzLmRhdGEuZnJhbWUoKQoKIyAgSG93IGRvIHRoaW5ncyBsb29rPwpjb3VudHNfZGF0YQpgYGAKPGJyIC8+CgojIyMgRm9yIGBkYXRhc2V0c19hbGxgLCBtYWtlIHRoZSBtb2RlbCBtYXRyaXgKYGBge3IgZGF0YXNldHNfYWxsOiBNYWtlIG1vZGVsIG1hdHJpeCwgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0V9CiMgIFVzZSB0aGUgImtleXMiIGNvbHVtbiB0byBpc29sYXRlIGRhdGFzZXRzIG9mIGludGVyZXN0CiNSRU1FTUJFUiBWYXJpYWJsZSBgZGF0YXNldHNgIGlzIGluaXRpYWxpemVkIGluIHRoZSBwcmVjZWRpbmcgY2h1bmsgCmNvbF9kYXRhIDwtIHNhbXBsZXNbc2FtcGxlcyRrZXlzICVpbiUgZGF0YXNldHMsIF0gJT4lCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lICAjSU1QT1JUQU5UIE91dHB1dCBhIGRhdGFmcmFtZSwgbm90IGEgdGliYmxlCiAgICB0aWJibGU6OmNvbHVtbl90b19yb3duYW1lcyguLCB2YXIgPSAia2V5cyIpICU+JSAgI0lNUE9SVEFOVCBIYXZlIHJvdyBuYW1lcwogICAgZHJvcGxldmVscygpIAoKIyAgTWFrZSBScnA2LW51bGwgbnVtZXJhdG9yLCB3aWxkLXR5cGUgZGVub21pbmF0b3IgYnkgZXhwbGljaXRseSByZW9yZGVyaW5nIHRoZQojKyBsZXZlbHMgb2YgdGhlIGZhY3RvciBjb2xfZGF0YSRzdHJhaW4KY29sX2RhdGEkc3RyYWluIDwtIGZhY3Rvcihjb2xfZGF0YSRzdHJhaW4sIGxldmVscyA9IGMoIldUIiwgInIxLW4iLCAicjYtbiIpKQoKIyAgRXhwbGljaXRseSByZW9yZGVyIHRoZSBsZXZlbHMgb2YgdGhlIGNvbF9kYXRhJHRlY2huaWNhbApjb2xfZGF0YSR0ZWNobmljYWwgPC0gZmFjdG9yKGNvbF9kYXRhJHRlY2huaWNhbCwgbGV2ZWxzID0gYygidGVjaDEiLCAidGVjaDIiKSkKCiMgIEhvdyBkbyB0aGluZ3MgbG9vaz8KY29sX2RhdGEKY29sX2RhdGEkc3RyYWluCmBgYAo8YnIgLz4KCiMjIyBGb3IgYGRhdGFzZXRzX2FsbGAsIGNvbnRpbnVlIGZhY3RvciBlbnVtZXJhdGlvbiAocm91Z2gtZHJhZnQpCmBgYHtyIGRhdGFzZXRzX2FsbDogY29udGludWUgZmFjdG9yIGVudW1lcmF0aW9uLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KIyAjICBTdXJ2ZXkgdGhlIGxldmVscyBhc3NvY2lhdGVkIHdpdGggbW9kZWwgdmFyaWFibGVzCiMgY29sbmFtZXMoY29sX2RhdGEpCiMgY29sX2RhdGEkc3RyYWluICU+JSBhcy5mYWN0b3IoKSAlPiUgdGFibGUoKQojIGNvbF9kYXRhJHJlcGxpY2F0ZSAlPiUgYXMuZmFjdG9yKCkgJT4lIHRhYmxlKCkKIyBjb2xfZGF0YSR0ZWNobmljYWwgJT4lIGFzLmZhY3RvcigpICU+JSB0YWJsZSgpCgojICBUcmFuc2Zvcm0gdGhlICJmb3JtYXQiIG9mIGZhY3RvcnMgZnJvbSBuYW1lcyB0byBwb3NpdGl2ZSBpbnRlZ2VycyB3aXRoCiMrIHNhcHBseSgpLCB3aGljaCBhcHBsaWVzIHRoZSBzd2l0Y2goKSBmdW5jdGlvbiB0byBlYWNoIGVsZW1lbnQKY29sX2RhdGEkbm9fc3RyYWluIDwtIHNhcHBseSgKICAgIGFzLmNoYXJhY3Rlcihjb2xfZGF0YSRzdHJhaW4pLAogICAgc3dpdGNoLAogICAgIldUIiA9IDEsCiAgICAicjEtbiIgPSAyLAogICAgInI2LW4iID0gMywKICAgIFVTRS5OQU1FUyA9IEZBTFNFCikKCmNvbF9kYXRhJG5vX3JlcGxpY2F0ZSA8LSBzYXBwbHkoCiAgICBhcy5jaGFyYWN0ZXIoY29sX2RhdGEkcmVwbGljYXRlKSwKICAgIHN3aXRjaCwKICAgICJyZXAxIiA9IDEsCiAgICAicmVwMiIgPSAyLAogICAgVVNFLk5BTUVTID0gRkFMU0UKKQoKY29sX2RhdGEkbm9fdGVjaG5pY2FsIDwtIHNhcHBseSgKICAgIGFzLmNoYXJhY3Rlcihjb2xfZGF0YSR0ZWNobmljYWwpLAogICAgc3dpdGNoLAogICAgInRlY2gxIiA9IDEsCiAgICAidGVjaDIiID0gMiwKICAgIFVTRS5OQU1FUyA9IEZBTFNFCikKCiMgIEhvdyBkbyB0aGluZ3MgbG9vaz8KY29sX2RhdGEKYGBgCjxiciAvPgoKIyMjIEZvciBgZGF0YXNldHNfYWxsYCwgbWFrZSB0aGUgYERFU2VxRGF0YVNldGAsIGBkZHNgCi0gVXNlIGBjb3VudHNfZGF0YWAgZm9yIHRoZSBgZmVhdHVyZUNvdW50YCB0YWxsaWVzCi0gVXNlIGBjb2xfZGF0YWAgZm9yIHNldHRpbmcgdXAgdGhlIEdMTQotIFVzZSBgcG9zX2luZm9gIGZvciBhZGRpbmcgZmVhdHVyZSBtZXRhZGF0YSwgc3Vic2VxdWVudCBzdWJzZXR0aW5nLCBldGMuCgpgYGB7ciBkYXRhc2V0c19hbGw6IG1ha2UgZGRzLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KZGRzIDwtIERFU2VxMjo6REVTZXFEYXRhU2V0RnJvbU1hdHJpeCgKICAgIGNvdW50RGF0YSA9IGNvdW50c19kYXRhLAogICAgY29sRGF0YSA9IGNvbF9kYXRhLAogICAgZGVzaWduID0gfiAxLAogICAgcm93UmFuZ2VzID0gcG9zX2luZm8KKQoKIyAgTWFrZSBhIGJhY2stdXAgb2YgdGhlIERFU2VxRGF0YVNldCBvYmplY3QKYmFrLmRkcyA8LSBkZHMKCiMgIyAgSG93IGRvIHRoaW5ncyBsb29rPwojIGRkcyAlPiUgQmlvY0dlbmVyaWNzOjpjb3VudHMoKSAlPiUgaGVhZCgpCiMgZGRzQHJvd1JhbmdlcwojIGRkc0BkZXNpZ24KIyBkZHNAYXNzYXlzCgojICMgIEZvciB0ZXN0cwojIHJtKGRkcykKYGBgCjxiciAvPgoKIyMjIFByZWZpbHRlciBgZGRzYApXZSBwcm9iYWJseSBkb24ndCBuZWVkIHRvIGRvIHRoaXMsIGJ1dCB0aGVuIGFnYWluIHdlIG1heSB3YW50IHRvLiBTb21lIHBlb3BsZQp0aGluayBpdCdzIGltcG9ydGFudDsgbXkgdGhpbmtpbmcgaGFzIGJlZW4gdGhhdCwgaWYgaXQgbWFrZXMgbXVjaCBvZiBhCmRpZmZlcmVuY2UgKGUuZy4sIGZyb20gZG9pbmcgZGltZW5zaW9uIHJlZHVjdGlvbiwgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcsCmV0Yy4pLCB0aGVuIHRoZXJlIG1heSBiZSBkZWVwZXIgcHJvYmxlbXMgd2l0aCB0aGUgZGF0YSAobm9pc2UsIGJhdGNoIGVmZmVjdHMsCmV0Yy4pLiBJZiBJIHJlbWVtYmVyIGNvcnJlY3RseSwgaWYgeW91IHdvcmsgdGhyb3VnaCBzZWN0aW9ucyBvZiB0aGUgYERFU2VxMmAKdmlnbmV0dGUgYW5kIG90aGVyIHZpZ25ldHRlcy93YWxrdGhyb3VnaHMgKGUuZy4sIFNvbmVzb24gZXQgYWwuLCAqRjEwMDAqKSwgdGhleQpwZXJmb3JtIHNvbWUgcm93LXdpc2UgcHJlZmlsdGVyaW5nLgoKYCNUT0RPYCBMZXQncyBrZWVwIHRoaXMgaW4gbWluZCBhbmQgdHJ5IGl0IGlmIHdlIGNvbWUgdG8gdGhpbmsgbG93bHkgZXhwcmVzc2VkCmdlbmVzIGFyZSBza2V3aW5nIHJlc3VsdHMuCgpgYGB7ciBwcmVmaWx0ZXIgZGRzLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KIyB0aHJlc2hvbGQgPC0gMTAwMAojIGRkc19maWx0IDwtIGRkc1tyb3dTdW1zKEJpb2NHZW5lcmljczo6Y291bnRzKGRkcykpID49IHRocmVzaG9sZCwgXQojCiMgIEJyZWFrZG93bgojICAgIDAgMTMxNjYKIyAgICAxIDEyNzg3CiMgICAgMiAxMjcxMQojICAgIDUgMTI1MTgKIyAgIDEwIDEyMjkyCiMgICAyMCAxMjAxNwojICAgNTAgMTE1MjkKIyAgMTAwIDExMTM2CiMgIDIwMCAxMDY1MwojICA1MDAgOTY3OAojIDEwMDAgODQ2MgojCiMgcm0odGhyZXNob2xkLCBkZHNfZmlsdCkKYGBgCjxiciAvPgo8YnIgLz4KCiMjIEkuIFJ1biBncm91cHdpc2UgYW5hbHlzZXMKIyMjIEdlbmVyYXRlIG5vcm1hbGl6ZWQgY291bnRzCiMjIyMgQ2FsY3VsYXRlIHZzdC1ub3JtYWxpemVkICh1bmJsaW5kZWQpIGNvdW50cwpgYGB7ciBJLiBDcmVhdGUgdnN0LW5vcm1hbGl6ZWQgY291bnRzLCBtZXNzYWdlPUZBTFNFfQp2c2QgPC0gREVTZXEyOjp2c3QoCiAgICBkZHNbZGRzQHJvd1JhbmdlcyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIsIF0sCiAgICBibGluZCA9IEZBTFNFCikKCm5vcm1fdiA8LSBsaW1tYTo6cmVtb3ZlQmF0Y2hFZmZlY3QoCiAgICBTdW1tYXJpemVkRXhwZXJpbWVudDo6YXNzYXkodnNkKSwKICAgIGJhdGNoID0gdnNkJHRlY2huaWNhbCwKICAgIGRlc2lnbiA9IG1vZGVsLm1hdHJpeCh+c3RyYWluLCBTdW1tYXJpemVkRXhwZXJpbWVudDo6Y29sRGF0YSh2c2QpKQopICU+JSAKICAgIGFzLmRhdGEuZnJhbWUoKQpub3JtX3YkZmVhdHVyZV9pbml0IDwtIGRkc0Byb3dSYW5nZXMkZmVhdHVyZV9pbml0WwogICAgZGRzQHJvd1JhbmdlcyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIKXQoKIyAgQXNzb2NpYXRlIG5vcm1hbGl6ZWQgdmFsdWVzIHdpdGggZmVhdHVyZSBtZXRhZGF0YQpub3JtX3YgPC0gZHBseXI6OmZ1bGxfam9pbigKICAgIG5vcm1fdiwKICAgIHRfZmNbdF9mYyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIsIDE6OV0sCiAgICBieSA9ICJmZWF0dXJlX2luaXQiCikgJT4lCiAgICBkcGx5cjo6YXNfdGliYmxlKCkKCnJtKHZzZCkKCiMgI1BSRVZJT1VTCiMgbm9ybV92IDwtIERFU2VxMjo6dnN0KAojICAgICBkZHNbZGRzQHJvd1JhbmdlcyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIsIF0sCiMgICAgIGJsaW5kID0gRkFMU0UKIyApICU+JQojICAgICBTdW1tYXJpemVkRXhwZXJpbWVudDo6YXNzYXkoKSAlPiUKIyAgICAgYXMuZGF0YS5mcmFtZSgpCiMgbm9ybV92JGZlYXR1cmVfaW5pdCA8LSBkZHNAcm93UmFuZ2VzJGZlYXR1cmVfaW5pdFsKIyAgICAgZGRzQHJvd1JhbmdlcyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIKIyBdCiMgCiMgIyAgQXNzb2NpYXRlIG5vcm1hbGl6ZWQgdmFsdWVzIHdpdGggZmVhdHVyZSBtZXRhZGF0YQojIG5vcm1fdiA8LSBkcGx5cjo6ZnVsbF9qb2luKAojICAgICBub3JtX3YsCiMgICAgIHRfZmNbdF9mYyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIsIDE6OV0sCiMgICAgIGJ5ID0gImZlYXR1cmVfaW5pdCIKIyApICU+JQojICAgICBkcGx5cjo6YXNfdGliYmxlKCkKYGBgCjxiciAvPgoKIyMjIyBDYWxjdWxhdGUgcmxvZy1ub3JtYWxpemVkICh1bmJsaW5kZWQpIGNvdW50cwpgYGB7ciBJLiBDcmVhdGUgcmxvZy1ub3JtYWxpemVkIGNvdW50cywgbWVzc2FnZT1GQUxTRX0KcmxkIDwtIERFU2VxMjo6cmxvZygKICAgIGRkc1tkZHNAcm93UmFuZ2VzJGdlbm9tZSA9PSAiU19jZXJldmlzaWFlIiwgXSwKICAgIGJsaW5kID0gRkFMU0UKKQoKbm9ybV9yIDwtIGxpbW1hOjpyZW1vdmVCYXRjaEVmZmVjdCgKICAgIFN1bW1hcml6ZWRFeHBlcmltZW50Ojphc3NheShybGQpLAogICAgYmF0Y2ggPSBybGQkdGVjaG5pY2FsLAogICAgZGVzaWduID0gbW9kZWwubWF0cml4KH5zdHJhaW4sIFN1bW1hcml6ZWRFeHBlcmltZW50Ojpjb2xEYXRhKHJsZCkpCikgJT4lIAogICAgYXMuZGF0YS5mcmFtZSgpCm5vcm1fciRmZWF0dXJlX2luaXQgPC0gZGRzQHJvd1JhbmdlcyRmZWF0dXJlX2luaXRbCiAgICBkZHNAcm93UmFuZ2VzJGdlbm9tZSA9PSAiU19jZXJldmlzaWFlIgpdCgojICBBc3NvY2lhdGUgbm9ybWFsaXplZCB2YWx1ZXMgd2l0aCBmZWF0dXJlIG1ldGFkYXRhCm5vcm1fciA8LSBkcGx5cjo6ZnVsbF9qb2luKAogICAgbm9ybV9yLAogICAgdF9mY1t0X2ZjJGdlbm9tZSA9PSAiU19jZXJldmlzaWFlIiwgMTo5XSwKICAgIGJ5ID0gImZlYXR1cmVfaW5pdCIKKSAlPiUKICAgIGRwbHlyOjphc190aWJibGUoKQoKcm0ocmxkKQoKIyAjUFJFVklPVVMKIyBub3JtX3IgPC0gREVTZXEyOjpybG9nKAojICAgICBkZHNbZGRzQHJvd1JhbmdlcyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIsIF0sCiMgICAgIGJsaW5kID0gRkFMU0UKIyApICU+JQojICAgICBTdW1tYXJpemVkRXhwZXJpbWVudDo6YXNzYXkoKSAlPiUKIyAgICAgYXMuZGF0YS5mcmFtZSgpCiMgbm9ybV9yJGZlYXR1cmVfaW5pdCA8LSBkZHNAcm93UmFuZ2VzJGZlYXR1cmVfaW5pdFsKIyAgICAgZGRzQHJvd1JhbmdlcyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIKIyBdCiMgCiMgIyAgQXNzb2NpYXRlIG5vcm1hbGl6ZWQgdmFsdWVzIHdpdGggZmVhdHVyZSBtZXRhZGF0YQojIG5vcm1fciA8LSBkcGx5cjo6ZnVsbF9qb2luKAojICAgICBub3JtX3IsCiMgICAgIHRfZmNbdF9mYyRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIsIDE6OV0sCiMgICAgIGJ5ID0gImZlYXR1cmVfaW5pdCIKIyApICU+JQojICAgICBkcGx5cjo6YXNfdGliYmxlKCkKYGBgCjxiciAvPgoKIyMjIyBDYWxjdWxhdGUgR2VUTU0tbm9ybWFsaXplZCBjb3VudHMKTW9yZSBkZXRhaWxzIG9uIHRoaXMgcmVsYXRpdmVseSBuZXcgbWV0aG9kIG9mIG5vcm1hbGl6YXRpb24sIHdoaWNoIGNvbWJpbmVzCmludGVyLSBhbmQgaW50cmEtc2FtcGxlIG5vcm1hbGl6YXRpb24gbWV0aG9kcyBhbmQgKGFwcGVhcnMgdG8pIHBlcmZvcm0gcXVpdGUKd2VsbDoKCi0gW0JhcmFpa2RhciBldCBhbC4gKFRydXR0bWFubiksICpFeHAgR2Vyb250b2wqIDIwMjNdKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzA1MzE1NTY1MjMwMDAyODEpCi0gW0JhcnJldHQgZXQgYWwuIChIYW1tYXJsdW5kKSwgKkczKiAyMDIxXShodHRwczovL2FjYWRlbWljLm91cC5jb20vZzNqb3VybmFsL2FydGljbGUvMTEvNy9qa2FiMTIxLzYyMjY0ODUpCi0gW0JlZHJlLCAqc2VsZi1wdWJsaXNoZWQqIDIwMjMgKG1vc3QgcmVjZW50IHVwZGF0ZSldKGh0dHBzOi8vd3d3LnJlbmVzaGJlZHJlLmNvbS9ibG9nL2V4cHJlc3Npb25fdW5pdHMuaHRtbCNnZXRtbS1tZXRob2QpCi0gW05lbHNvbiBldCBhbC4gKFdpbGtpbnMpLCAqTmF0IE1pY3JvYmlvbCogMjAyMl0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DOTQxODAwMS8pCi0gW1NtaWQgZXQgYWwuIChTaWV1d2VydHMpLCAqQk1DIEJpb2luZiogMjAxOF0oaHR0cHM6Ly9ibWNiaW9pbmZvcm1hdGljcy5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3MxMjg1OS0wMTgtMjI0Ni03KQotIFtXYWxrZXIgZXQgYWwuIChLYWluZXIpLCAqQ29tcHV0IFN0cnVjdCBCaW90ZWNobm9sIEoqIDIwMjJdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzkyNjAyNjAvKQotIFtaYXR6bWFuIGV0IGFsLiAoU2hsaWVuKSwgKlNjaSBBZHYqIDIwMjJdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzk2ODM3MjMvKQoKYGBge3IgSS4gQ3JlYXRlIEdlVE1NLW5vcm1hbGl6ZWQgY291bnRzLCBtZXNzYWdlPUZBTFNFfQojICNQUkVWSU9VUwojICMgIElzb2xhdGUgcmF3IGNvdW50cyBmb3Igc2FtcGxlcyBvZiBpbnRlcmVzdAojIHJhdyA8LSBkZHMgJT4lCiMgICAgIFN1bW1hcml6ZWRFeHBlcmltZW50Ojphc3NheSgpICU+JQojICAgICBhcy5kYXRhLmZyYW1lKCkKIyByYXckZmVhdHVyZV9pbml0IDwtIGRkc0Byb3dSYW5nZXMkZmVhdHVyZV9pbml0CiMgCiMgIyAgQXNzb2NpYXRlIG5vbi1ub3JtYWxpemVkIHZhbHVlcyB3aXRoIGZlYXR1cmUgbWV0YWRhdGEKIyByYXcgPC0gZHBseXI6OmZ1bGxfam9pbigKIyAgICAgcmF3LAojICAgICB0X2ZjWywgYyhzZXEoMSw5KSldLAojICAgICBieSA9ICJmZWF0dXJlX2luaXQiCiMgKSAlPiUKIyAgICAgZHBseXI6OmFzX3RpYmJsZSgpCiMgCiMgIyAgQ2FsY3VsYXRlIGNvdW50cyBwZXIga2Igb2YgZ2VuZSBsZW5ndGggKGkuZS4sIGNvcnJlY3QgY291bnRzIGZvciBnZW5lCiMgIysgbGVuZ3RoKTsgZ2VuZSBsZW5ndGggaXMgaW5pdGlhbGx5IGluIGJwIGFuZCBjb252ZXJ0ZWQgdG8ga2IKIyBycGsgPC0gKChyYXdbLCAxOjE3XSAqIDEwXjMpIC8gcmF3JGxlbmd0aCkKIyBycGtbLCAxODoyNl0gPC0gcmF3WywgMTg6MjZdCiMgCiMgIyAgQ2FsY3VsYXRlIG5vcm1hbGl6YXRpb24gZmFjdG9ycyB1c2luZyB0aGUgcmF3IHNwaWtlLWluIChLLiBsYWN0aXMpIGNvdW50cwojIG5vcm1fS0wgPC0gZWRnZVI6OmNhbGNOb3JtRmFjdG9ycygKIyAgICAgcmF3WyhycGskZ2Vub21lID09ICJLX2xhY3RpcyIpLCBdWywgMToxN10KIyApCiMgCiMgIyAgQ3JlYXRlIGZhY3RvciBmb3IgY2F0ZWdvcmllcyAoZ3JvdXBzKQojIG1vZGVsX3ZhcmlhYmxlcyA8LSBzdHJpbmdyOjpzdHJfc3BsaXQoY29sbmFtZXMocnBrWywgMToxN10pLCAiXyIpICU+JQojICAgICBhcy5kYXRhLmZyYW1lKAojICAgICAgICAgcm93Lm5hbWVzID0gYygKIyAgICAgICAgICAgICAic2FtcGxlIiwgInN0YWdlIiwgImRheSIsICJraXQiLCAidHgiLCAiYXV4IiwgInRjIiwgInJlcCIsICJ0ZWNoIgojICAgICAgICAgKSwKIyAgICAgICAgIGNvbC5uYW1lcyA9IHBhc3RlMCgicyIsIGMoMToxNykpCiMgICAgICkgJT4lCiMgICAgIHQoKSAlPiUKIyAgICAgdGliYmxlOjphc190aWJibGUoKQojIAojIGdyb3VwIDwtIGZhY3RvcigKIyAgICAgIyBTZWNvbmQgbGV2ZWwgaXMgbnVtZXJhdG9yLCBmaXJzdCBsZXZlbCBpcyBkZW5vbWluYXRvcgojICAgICBtb2RlbF92YXJpYWJsZXMkc2FtcGxlLAojICAgICBsZXZlbHMgPSBjKCJXVCIsICJyNi1uIikKIyApCiMgCiMgcm0obW9kZWxfdmFyaWFibGVzKQojIAojICMgIENyZWF0ZSBlZGdlUiBER0VMaXN0IG9iamVjdCBjb21wb3NlZCBvZiBTLiBjZXJldmlzaWFlIGNvdW50cyBwZXIga2IgZ2VuZQojICMrIGxlbmd0aAojIGRnZWwgPC0gZWRnZVI6OkRHRUxpc3QoCiMgICAgIGNvdW50cyA9IHJwa1tycGskZ2Vub21lID09ICJTX2NlcmV2aXNpYWUiLCBdWywgMToxN10sCiMgICAgIGdyb3VwID0gZ3JvdXAKIyApCiMgCiMgIyAgSW4gdGhlIERHRUxpc3Qgb2JqZWN0LCBpbmNsdWRlIHRoZSBub3JtYWxpemF0aW9uIGZhY3RvcnMgY2FsY3VsYXRlZCBmcm9tCiMgIysgc3Bpa2UtaW4gaW5mb3JtYXRpb24KIyBkZ2VsJHNhbXBsZXMkbm9ybS5mYWN0b3JzIDwtIG5vcm1fS0wKIyAKIyAjICBDaGVjayB0aGF0IHRoZSBub3JtYWxpemF0aW9uIGZhY3RvcnMgZm9yIGVhY2ggbGlicmFyeSBhcmUgYXBwcm9wcmlhdGVseQojICMrIGFzc2lnbmVkCiMgZGdlbCRzYW1wbGVzCiMgCiMgIyAgU2NhbGUgdGhlIHZhbHVlcyB0byBjb3VudHMtcGVyLW1pbGxpb24KIyBub3JtX2cgPC0gZWRnZVI6OmNwbShkZ2VsKSAlPiUgdGliYmxlOjphc190aWJibGUoKQojIG5vcm1fZ1ssIDE4OjI2XSA8LSBycGtbcnBrJGdlbm9tZSA9PSAiU19jZXJldmlzaWFlIiwgMTg6MjZdCiMgbm9ybV9nCiMgCiMgIyAgQ2xlYW4gdXAgdW5uZWVkZWQgdmFyaWFibGVzCiMgcm0ocmF3LCBycGssIG5vcm1fS0wsIGdyb3VwKQojIHJtKGRnZWwpICAjVE9ETyBEZWxldGUgZGdlbD8gT3IgdXNlIGl0IGZvciB0cnlpbmcgb3V0IERFIGFuYWx5c2VzIHdpdGggZWRnZVI/CmBgYAo8YnIgLz4KCiMjIyMgQ2FsY3VsYXRlIFRQTS1ub3JtYWxpemVkIGNvdW50cwpgYGB7ciBJLiBDYWxjdWxhdGUgVFBNLW5vcm1hbGl6ZWQgY291bnRzLCBtZXNzYWdlPUZBTFNFfQojICNQUkVWSU9VUwojICMgIElzb2xhdGUgcmF3IGNvdW50cyBmb3Igc2FtcGxlcyBvZiBpbnRlcmVzdAojIHJhdyA8LSBkZHMgJT4lCiMgICAgIFN1bW1hcml6ZWRFeHBlcmltZW50Ojphc3NheSgpICU+JQojICAgICBhcy5kYXRhLmZyYW1lKCkKIyByYXckZmVhdHVyZV9pbml0IDwtIGRkc0Byb3dSYW5nZXMkZmVhdHVyZV9pbml0CiMgCiMgIyAgQXNzb2NpYXRlIG5vbi1ub3JtYWxpemVkIHZhbHVlcyB3aXRoIGZlYXR1cmUgbWV0YWRhdGEKIyByYXcgPC0gZHBseXI6OmZ1bGxfam9pbigKIyAgICAgcmF3LAojICAgICB0X2ZjWywgMTo5XSwKIyAgICAgYnkgPSAiZmVhdHVyZV9pbml0IgojICkgJT4lCiMgICAgIGRwbHlyOjphc190aWJibGUoKQojIAojICMgIENhbGN1bGF0ZSBjb3VudHMgcGVyIGtiIG9mIGdlbmUgbGVuZ3RoIChpLmUuLCBjb3JyZWN0IGNvdW50cyBmb3IgZ2VuZQojICMrIGxlbmd0aCBvciBkbyBhbiAiUlBLIG5vcm1hbGl6YXRpb24iKTsgdGhlbiwgZGl2aWRlIFJQSy1ub3JtYWxpemVkIGVsZW1lbnRzCiMgIysgYnkgdGhlIHN1bSBvZiBzYW1wbGUgUlBLIGRpdmlkZWQgYnkgb25lIG1pbGxpb246IHRoaXMgZG9lcyB0aGUgYWN0dWFsIFRQTQojICMrIG5vcm1hbGl6YXRpb24KIyBycGsgPC0gdHBtIDwtICgocmF3WywgMToxN10gKiAxMF4zKSAvIHJhdyRsZW5ndGgpCiMgZm9yIChpIGluIDE6bmNvbChycGspKSB7CiMgICAgIHRwbVssIGldIDwtIChycGtbLCBpXSAvIHN1bShycGtbLCBpXSAvIDFlNikpCiMgfQojIAojIHRwbVssIDE4OjI2XSA8LSByYXdbLCAxODoyNl0KIyBub3JtX3QgPC0gdHBtW3RwbSRnZW5vbWUgPT0gIlNfY2VyZXZpc2lhZSIsIF0KIyAKIyBybShyYXcsIHJwaywgdHBtKQojIAojICNDSEVDSwojICMgIENoZWNrIHRoYXQgbXkgY2FsY3VsYXRpb24gYWJvdmUgaXMgYWN0dWFsbHkgcHJvZHVjaW5nIFRQTS1ub3JtYWxpemVkIHZhbHVlczoKIyAjKyAjUVVFU1RJT04gMS8yIERvIG15IHZhbHVlcyBtYXRjaCB0aGUgb3V0cHV0IGZyb20gY29kZSBieSBNaWtlIExvdmUgKGF1dGhvcgojICMrICNRVUVTVElPTiAyLzIgb2YgREVTZXEyKSBwb3N0ZWQgYXQgc3VwcG9ydC5iaW9jb25kdWN0b3Iub3JnL3AvOTEyMTgvPwojICMgeCA8LSByYXdbLCAxOjVdIC8gcmF3JGxlbmd0aAojICMgdGVzdCA8LSB0KCh0KHgpICogMWU2KSAvIGNvbFN1bXMoeCkpCiMgIyB0ZXN0IDwtIHRlc3QgJT4lIGFzLmRhdGEuZnJhbWUoKQojICMgaWRlbnRpY2FsKAojICMgICAgICAgcm91bmQodGVzdCRgbjMtZF9RX2RheTdfdGNuX05fYXV4LVRfdGMtRl9yZXAxX3RlY2gxYCwgZGlnaXRzID0gMyksCiMgIyAgICAgcm91bmQobm9ybV90JGBuMy1kX1FfZGF5N190Y25fTl9hdXgtVF90Yy1GX3JlcDFfdGVjaDFgLCBkaWdpdHMgPSAzKQojICMgKSAgIyBbMV0gVFJVRQojICMgICNBTlNXRVIgQmFzaWNhbGx5LCB0aGUgY2FsY3VsYXRpb25zIHJlc3VsdCBpbiBlcXVpdmFsZW50IHJlc3VsdHMKYGBgCjxiciAvPgoKIyMjIFJ1biBQQ0Egd2l0aCB2YXJpb3VzbHkgbm9ybWFsaXplZCBjb3VudHMKIyMjIyBQYXJ0IDEKYGBge3IgSS4gUnVuIFBDQSB3aXRoIHZhcmlvdXNseSBub3JtYWxpemVkIGNvdW50cywgbWVzc2FnZT1GQUxTRX0KIyAgTWFrZSB0aGUgZm9sbG93aW5nIGNvZGUgZ2VuZXJpYyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojKyAuLi5zbyB0aGF0IHdlIGNhbiB0cnkgaXQgd2l0aCBkaWZmZXJlbnQgbm9ybWFsaXphdGlvbiBvYmplY3RzIChjb3VudHMKIysgbm9ybWFsaXplZCBpbiBkaWZmZXJlbnQgd2F5cykKIyBub3JtIDwtIG5vcm1fdgpub3JtIDwtIG5vcm1fcgojIG5vcm0gPC0gbm9ybV9nCiMgbm9ybSA8LSBub3JtX3QKI05PVEUgMS8zIG5vcm1fZyBhbmQgbm9ybV90IGFwcGVhciB0byBiZSB0aGUgYmVzdCBwZXJmb3JtaW5nOyBub3JtX3IgKGJsaW5kZWQKI05PVEUgMi8zIG9yIG5vdCkgY2x1c3RlcnMgYWxsIHNhbXBsZXMgdG9nZXRoZXIgcmVnYXJkbGVzcyBvZiBtb2RlbCB2YXJpYWJsZQojTk9URSAzLzMgJ3N0cmFpbicKCiMgIENyZWF0ZSBhIFBDQXRvb2xzICJwY2EiIFM0IG9iamVjdCBmb3IgdGhlIG5vcm1hbGl6ZWQgY291bnRzIC0tLS0tLS0tLS0tLS0tLS0KIysgQXNzaWduIHVuaXF1ZSByb3cgbmFtZXMgdG9vCm9ial9wY2EgPC0gUENBdG9vbHM6OnBjYSgKICAgIG5vcm1bLCAxOjddLAogICAgbWV0YWRhdGEgPSBkZHNbZGRzQHJvd1JhbmdlcyRnZW5vbWUgIT0gIktfbGFjdGlzIiwgXUBjb2xEYXRhCikKcm93bmFtZXMob2JqX3BjYSRsb2FkaW5ncykgPC0gbWFrZS5uYW1lcygKICAgIGRkc1tkZHNAcm93UmFuZ2VzJGdlbm9tZSAhPSAiS19sYWN0aXMiLCBdQHJvd1JhbmdlcyRmZWF0dXJlLAogICAgdW5pcXVlID0gVFJVRQopCiMgY29sbmFtZXMob2JqX3BjYSRsb2FkaW5ncykKCgojICBEZXRlcm1pbmUgInNpZ25pZmljYW50IiBQQ3Mgd2l0aCBIb3JuJ3MgcGFyYWxsZWwgYW5hbHlzaXMgLS0tLS0tLS0tLS0tLS0tLS0tCiMrIFNlZSBIb3JuLCAxOTY1Cmhvcm4gPC0gUENBdG9vbHM6OnBhcmFsbGVsUENBKG1hdCA9IG5vcm1bLCAxOjddKQojIGhvcm4kbgoKCiMgIERldGVybWluZSAic2lnbmlmaWNhbnQiIHByaW5jaXBsZSBjb21wb25lbnRzIHdpdGggdGhlIGVsYm93IG1ldGhvZCAtLS0tLS0tLS0KIysgU2VlIEJ1amEgYW5kIEV5dWJvZ2x1LCAxOTkyCmVsYm93IDwtIFBDQXRvb2xzOjpmaW5kRWxib3dQb2ludChvYmpfcGNhJHZhcmlhbmNlKQojIGVsYm93CgoKIyAgRXZhbHVhdGUgY3VtdWxhdGl2ZSBwcm9wb3J0aW9uIG9mIGV4cGxhaW5lZCB2YXJpYW5jZSB3aXRoIGEgc2NyZWUgcGxvdCAtLS0tLQpzY3JlZSA8LSBkcmF3X3NjcmVlX3Bsb3Qob2JqX3BjYSwgaG9ybiA9IGhvcm4kbiwgZWxib3cgPSBlbGJvdykKc2NyZWUKIyBzYXZlX3RpdGxlIDwtIHBhc3RlMCgicGFuZWwtcGxvdCIsICIuIiwgInNjcmVlIiwgIi5wZGYiKQojIGdncGxvdDI6Omdnc2F2ZShwYXN0ZTAoYXJncyRkaXJlY3Rvcnlfb3V0LCAiLyIsIHNhdmVfdGl0bGUpLCBzY3JlZSkKI1RPRE8gV29yayB1cCBzb21lIGxvZ2ljIGZvciBsb2NhdGlvbihzKSBmb3Igb3V0ZmlsZXMKYGBgCjxiciAvPgoKIyMjIyBQYXJ0IDIKYGBge3IgSS4gUnVuIFBDQSB3aXRoIHZhcmlvdXNseSBub3JtYWxpemVkIGNvdW50cyAocGFydCAyKSwgbWVzc2FnZT1GQUxTRX0KIyAgU2F2ZSBjb21wb25lbnQgbG9hZGluZyB2ZWN0b3JzIGluIHRoZWlyIG93biBkYXRhIGZyYW1lIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQpsb2FkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKG9ial9wY2EkbG9hZGluZ3MpCgojICBFdmFsdWF0ZSB0aGUgY29tcG9uZW50IGxvYWRpbmcgdmVjdG9ycyBmb3IgdGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBQQ3MKIysgaWRlbnRpZmllZCB2aWEgdGhlIGVsYm93IG1ldGhvZCBwbHVzIHR3bwpQQ3MgPC0gcGFzdGUwKCJQQyIsIDE6KGFzLm51bWVyaWMoZWxib3cpICsgMikpCnRvcF9sb2FkaW5nc19hbGwgPC0gbGFwcGx5KAogICAgUENzLCBnZXRfdG9wX2xvYWRpbmdzLCB4ID0gbG9hZGluZ3MsIHogPSAiYWxsIiwgYSA9IFRSVUUKKQp0b3BfbG9hZGluZ3NfcG9zIDwtIGxhcHBseSgKICAgIFBDcywgZ2V0X3RvcF9sb2FkaW5ncywgeCA9IGxvYWRpbmdzLCB6ID0gInBvcyIsIGEgPSBUUlVFCikKdG9wX2xvYWRpbmdzX25lZyA8LSBsYXBwbHkoCiAgICBQQ3MsIGdldF90b3BfbG9hZGluZ3MsIHggPSBsb2FkaW5ncywgeiA9ICJuZWciLCBhID0gVFJVRQopCgpuYW1lcyh0b3BfbG9hZGluZ3NfYWxsKSA8LQogICAgbmFtZXModG9wX2xvYWRpbmdzX3BvcykgPC0KICAgIG5hbWVzKHRvcF9sb2FkaW5nc19uZWcpIDwtCiAgICBQQ3MKIyBybShQQ3MpCiMgdG9wX2xvYWRpbmdzX2FsbCRQQzEgJT4lIGhlYWQobiA9IDIwKQojIHRvcF9sb2FkaW5nc19wb3MkUEMxICU+JSBoZWFkKG4gPSAyMCkKIyB0b3BfbG9hZGluZ3NfbmVnJFBDMSAlPiUgaGVhZChuID0gMjApCgoKIyAgQW5hbHl6ZSBwb3NpdGl2ZSwgbmVnYXRpdmUgbG9hZGluZ3Mgb24gYXhlcyBvZiBiaXBsb3RzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQojKyBMb29rIGF0IHRoZSB0b3AgMTUgcGVyIGF4aXMKaW1hZ2VzIDwtIGxpc3QoKQptYXQgPC0gY29tYm4oUENzLCAyKQpmb3IoaSBpbiAxOm5jb2wobWF0KSkgewogICAgIyBpIDwtIDEKICAgIGogPC0gbWF0WywgaV0KICAgIAogICAgUENfeCA8LSB4X2xhYmVsIDwtIGpbMV0KICAgIFBDX3kgPC0geV9sYWJlbCA8LSBqWzJdCiAgICAKICAgIGltYWdlc1tbcGFzdGUwKCJQQ0F0b29scy4iLCBQQ194LCAiLnYuIiwgUENfeSldXSA8LSBwbG90X2JpcGxvdCgKICAgICAgICBwY2EgPSBvYmpfcGNhLAogICAgICAgIFBDX3ggPSBQQ194LAogICAgICAgIFBDX3kgPSBQQ195LAogICAgICAgIGxvYWRpbmdzX3Nob3cgPSBGQUxTRSwKICAgICAgICBsb2FkaW5nc19uID0gMCwKICAgICAgICBtZXRhX2NvbG9yID0gInN0cmFpbiIsCiAgICAgICAgbWV0YV9zaGFwZSA9ICJyZXBsaWNhdGUiLAogICAgICAgIHhfbWluID0gLTIwLCAgIyAtMTIwMDAwLCAgIyAtNjYsCiAgICAgICAgeF9tYXggPSAyMCwgICMgMTIwMDAwLCAgIyA2NiwKICAgICAgICB5X21pbiA9IC0yMCwgICMgLTUwMDAwLCAgIyAtNTAsCiAgICAgICAgeV9tYXggPSAyMCAgIyA1MDAwMCAgIyA1MAogICAgKQogICAgCiAgICAjSEVSRQogICAgaW1hZ2VzW1twYXN0ZTAoIktBLiIsIFBDX3gsICIudi4iLCBQQ195KV1dIDwtCiAgICAgICAgcGxvdF9wb3NfbmVnX2xvYWRpbmdzX2VhY2hfYXhpcygKICAgICAgICAgICAgZGZfYWxsID0gbG9hZGluZ3MsCiAgICAgICAgICAgIGRmX3BvcyA9IHRvcF9sb2FkaW5nc19wb3MsCiAgICAgICAgICAgIGRmX25lZyA9IHRvcF9sb2FkaW5nc19uZWcsCiAgICAgICAgICAgIFBDX3ggPSBQQ194LAogICAgICAgICAgICBQQ195ID0gUENfeSwKICAgICAgICAgICAgcm93X3N0YXJ0ID0gMSwKICAgICAgICAgICAgcm93X2VuZCA9IDE1LCAgIyAzMAogICAgICAgICAgICB4X21pbiA9IC0wLjE1LCAgIyAtMC4xNSwgICMgLTEuMCwKICAgICAgICAgICAgeF9tYXggPSAwLjE1LCAgIyAwLjE1LCAgIyAxLjAsCiAgICAgICAgICAgIHlfbWluID0gLTAuMTUsICAjIC0wLjEsICAjIC0wLjUsCiAgICAgICAgICAgIHlfbWF4ID0gMC4xNSwgICMgMC4xLCAgIyAwLjUsCiAgICAgICAgICAgIHhfbnVkZ2UgPSAwLjAyLCAgIyAwLjAyLCAgIyAwLjA0LAogICAgICAgICAgICB5X251ZGdlID0gMC4wNCwgICMgMC4wNCwgICMgMC4wMiwKICAgICAgICAgICAgeF9sYWJlbCA9IHhfbGFiZWwsCiAgICAgICAgICAgIHlfbGFiZWwgPSB5X2xhYmVsLAogICAgICAgICAgICBjb2xfbGluZV9wb3MgPSAiYmxhY2siLAogICAgICAgICAgICBjb2xfbGluZV9uZWcgPSAicmVkIiwKICAgICAgICAgICAgY29sX3NlZ19wb3MgPSAiZ3JleSIsCiAgICAgICAgICAgIGNvbF9zZWdfbmVnID0gImdyZXkiCiAgICAgICAgKQogICAgCiAgICBpbWFnZXNbW3Bhc3RlMCgiS0EuIiwgUENfeCwgIi52LiIsIFBDX3kpXV0KfQoKIyAgSG93IGRvIHRoaW5ncyBsb29rPwppbWFnZXMkUENBdG9vbHMuUEMxLnYuUEMyCmltYWdlcyRLQS5QQzEudi5QQzIkUENfeF9wb3MKaW1hZ2VzJEtBLlBDMS52LlBDMiRQQ194X25lZwppbWFnZXMkS0EuUEMxLnYuUEMyJFBDX3lfcG9zCmltYWdlcyRLQS5QQzEudi5QQzIkUENfeV9uZWcKCiMgaW1hZ2VzJFBDQXRvb2xzLlBDMS52LlBDMwojIGltYWdlcyRLQS5QQzEudi5QQzMkUENfeF9wb3MKIyBpbWFnZXMkS0EuUEMxLnYuUEMzJFBDX3hfbmVnCiMgaW1hZ2VzJEtBLlBDMS52LlBDMyRQQ195X3BvcwojIGltYWdlcyRLQS5QQzEudi5QQzMkUENfeV9uZWcKIyAKIyBpbWFnZXMkUENBdG9vbHMuUEMxLnYuUEM0CiMgaW1hZ2VzJEtBLlBDMS52LlBDNCRQQ194X3BvcwojIGltYWdlcyRLQS5QQzEudi5QQzQkUENfeF9uZWcKIyBpbWFnZXMkS0EuUEMxLnYuUEM0JFBDX3lfcG9zCiMgaW1hZ2VzJEtBLlBDMS52LlBDNCRQQ195X25lZwojIAojIGltYWdlcyRQQ0F0b29scy5QQzIudi5QQzMKIyBpbWFnZXMkS0EuUEMyLnYuUEMzJFBDX3hfcG9zCiMgaW1hZ2VzJEtBLlBDMi52LlBDMyRQQ194X25lZwojIGltYWdlcyRLQS5QQzIudi5QQzMkUENfeV9wb3MKIyBpbWFnZXMkS0EuUEMyLnYuUEMzJFBDX3lfbmVnCiMgCiMgaW1hZ2VzJFBDQXRvb2xzLlBDMi52LlBDNAojIGltYWdlcyRLQS5QQzIudi5QQzQkUENfeF9wb3MKIyBpbWFnZXMkS0EuUEMyLnYuUEM0JFBDX3hfbmVnCiMgaW1hZ2VzJEtBLlBDMi52LlBDNCRQQ195X3BvcwojIGltYWdlcyRLQS5QQzIudi5QQzQkUENfeV9uZWcKIyAKIyBpbWFnZXMkUENBdG9vbHMuUEMzLnYuUEM0CiMgaW1hZ2VzJEtBLlBDMy52LlBDNCRQQ194X3BvcwojIGltYWdlcyRLQS5QQzMudi5QQzQkUENfeF9uZWcKIyBpbWFnZXMkS0EuUEMzLnYuUEM0JFBDX3lfcG9zCiMgaW1hZ2VzJEtBLlBDMy52LlBDNCRQQ195X25lZwoKIyBpbWFnZXMkUENBdG9vbHMuUEMxLnYuUEMzCiMgaW1hZ2VzJEtBLlBDMS52LlBDMwojIGltYWdlcyRQQ0F0b29scy5QQzEudi5QQzQKIyBpbWFnZXMkS0EuUEMxLnYuUEM0CiMgaW1hZ2VzJFBDQXRvb2xzLlBDMi52LlBDMwojIGltYWdlcyRLQS5QQzIudi5QQzMKYGBgCjxiciAvPgoKIyMjIyBQYXJ0IDMKYGBge3IgSS4gUnVuIFBDQSB3aXRoIHZhcmlvdXNseSBub3JtYWxpemVkIGNvdW50cyAocGFydCAzKSwgbWVzc2FnZT1GQUxTRX0KIyBmb3IoaSBpbiAxOmxlbmd0aChuYW1lcyhpbWFnZXMpKSkgewojICAgICAjIGkgPC0gMgojICAgICB2ZWN0b3JfbmFtZXMgPC0gbmFtZXMoaW1hZ2VzKSAlPiUgc3RyaW5ncjo6c3RyX3NwbGl0KCJcXC4iKQojICAgICAKIyAgICAgaWYodmVjdG9yX25hbWVzW1tpXV1bMV0gPT0gIlBDQXRvb2xzIikgewojICAgICAgICAgc2F2ZV90aXRsZSA8LSBwYXN0ZTAoInBhbmVsLXBsb3QiLCAiLiIsIG5hbWVzKGltYWdlcylbaV0sICIucGRmIikKIyAgICAgICAgIGdncGxvdDI6Omdnc2F2ZSgKIyAgICAgICAgICAgICBwYXN0ZTAoYXJncyRkaXJlY3Rvcnlfb3V0LCAiLyIsIHNhdmVfdGl0bGUpLCBpbWFnZXNbW2ldXQojICAgICAgICAgKQojICAgICB9IGVsc2UgaWYodmVjdG9yX25hbWVzW1tpXV1bMV0gPT0gIktBIikgewojICAgICAgICAgc2F2ZV90aXRsZSA8LSBwYXN0ZTAoCiMgICAgICAgICAgICAgInBhbmVsLXBsb3QiLCAiLiIsIG5hbWVzKGltYWdlcylbaV0sICIuMS14LXBvc2l0aXZlLnBkZiIKIyAgICAgICAgICkKIyAgICAgICAgIGdncGxvdDI6Omdnc2F2ZSgKIyAgICAgICAgICAgICBwYXN0ZTAoYXJncyRkaXJlY3Rvcnlfb3V0LCAiLyIsIHNhdmVfdGl0bGUpLCBpbWFnZXNbW2ldXVtbMV1dCiMgICAgICAgICApCiMgICAgICAgICAKIyAgICAgICAgIHNhdmVfdGl0bGUgPC0gcGFzdGUwKAojICAgICAgICAgICAgICJwYW5lbC1wbG90IiwgIi4iLCBuYW1lcyhpbWFnZXMpW2ldLCAiLjIteS1wb3NpdGl2ZS5wZGYiCiMgICAgICAgICApCiMgICAgICAgICBnZ3Bsb3QyOjpnZ3NhdmUoCiMgICAgICAgICAgICAgcGFzdGUwKGFyZ3MkZGlyZWN0b3J5X291dCwgIi8iLCBzYXZlX3RpdGxlKSwgaW1hZ2VzW1tpXV1bWzJdXQojICAgICAgICAgKQojICAgICAgICAgCiMgICAgICAgICBzYXZlX3RpdGxlIDwtIHBhc3RlMCgKIyAgICAgICAgICAgICAicGFuZWwtcGxvdCIsICIuIiwgbmFtZXMoaW1hZ2VzKVtpXSwgIi4zLXgtbmVnYXRpdmUucGRmIgojICAgICAgICAgKQojICAgICAgICAgZ2dwbG90Mjo6Z2dzYXZlKAojICAgICAgICAgICAgIHBhc3RlMChhcmdzJGRpcmVjdG9yeV9vdXQsICIvIiwgc2F2ZV90aXRsZSksIGltYWdlc1tbaV1dW1szXV0KIyAgICAgICAgICkKIyAgICAgICAgIAojICAgICAgICAgc2F2ZV90aXRsZSA8LSBwYXN0ZTAoCiMgICAgICAgICAgICAgInBhbmVsLXBsb3QiLCAiLiIsIG5hbWVzKGltYWdlcylbaV0sICIuNC15LW5lZ2F0aXZlLnBkZiIKIyAgICAgICAgICkKIyAgICAgICAgIGdncGxvdDI6Omdnc2F2ZSgKIyAgICAgICAgICAgICBwYXN0ZTAoYXJncyRkaXJlY3Rvcnlfb3V0LCAiLyIsIHNhdmVfdGl0bGUpLCBpbWFnZXNbW2ldXVtbNF1dCiMgICAgICAgICApCiMgICAgIH0KIyB9CiNUT0RPIFdvcmsgdXAgc29tZSBsb2dpYyBmb3IgbG9jYXRpb24ocykgZm9yIG91dGZpbGVzCgoKIyAgUGxvdCB0aGUgdG9wIGZlYXR1cmVzIG9uIGFuIGF4aXMgb2YgY29tcG9uZW50IGxvYWRpbmcgcmFuZ2UgLS0tLS0tLS0tLS0tLS0tLQojKyAuLi50byB2aXN1YWxpemUgdGhlIHRvcCB2YXJpYWJsZXMgKGZlYXR1cmVzKSB0aGF0IGRyaXZlIHZhcmlhbmNlIGFtb25nCiMrIHByaW5jaXBhbCBjb21wb25lbnRzIG9mIGludGVyZXN0CnBfbG9hZGluZ3MgPC0gUENBdG9vbHM6OnBsb3Rsb2FkaW5ncygKICAgIG9ial9wY2EsCiAgICBjb21wb25lbnRzID0gZ2V0Q29tcG9uZW50cyhvYmpfcGNhLCAxKSwKICAgICMgY29tcG9uZW50cyA9IGdldENvbXBvbmVudHMob2JqX3BjYSwgMTo1KSwKICAgIHJhbmdlUmV0YWluID0gMC4wNSwKICAgIGFic29sdXRlID0gRkFMU0UsCiAgICBjb2wgPSBjKCIjNzg1RUYwNzUiLCAiI0ZGRkZGRjc1IiwgIiNGRTYxMDA3NSIpLAogICAgdGl0bGUgPSAiTG9hZGluZ3MgcGxvdCIsCiAgICBzdWJ0aXRsZSA9ICJUb3AgNSUgb2YgdmFyaWFibGVzIChpLmUuLCBmZWF0dXJlcykiLAogICAgIyBzaGFwZVNpemVSYW5nZSA9IGMoNCwgMTYpLAogICAgYm9yZGVyQ29sb3VyID0gIiMwMDAwMDAiLAogICAgYm9yZGVyV2lkdGggPSAwLjIsCiAgICBncmlkbGluZXMubWFqb3IgPSBUUlVFLAogICAgZ3JpZGxpbmVzLm1pbm9yID0gVFJVRSwKICAgIGF4aXNMYWJTaXplID0gMTAsCiAgICBsYWJTaXplID0gMywgICMgbGFiZWxfc2l6ZQogICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgd2lkdGhDb25uZWN0b3JzID0gMC4yLAogICAgdHlwZUNvbm5lY3RvcnMgPSAnY2xvc2VkJywKICAgIGNvbENvbm5lY3RvcnMgPSAnYmxhY2snCikgKwogICAgIyBnZ3Bsb3QyOjpjb29yZF9mbGlwKCkgKwogICAgdGhlbWVfc2xpY2tfbm9fbGVnZW5kCnBfbG9hZGluZ3MKI1RPRE8gV29yayB1cCBzb21lIGxvZ2ljIGZvciBzYXZpbmcgdGhlIHBsb3QKCgojICBFdmFsdWF0ZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBQQ3MgYW5kIG1vZGVsIHZhcmlhYmxlcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMrIEFuc3dlciwgIldoYXQgaXMgZHJpdmluZyBiaW9sb2dpY2FsbHkgc2lnbmlmaWNhbnQgdmFyaWFuY2UgaW4gb3VyIGRhdGE/IgpQQ19jb3IgPC0gUENBdG9vbHM6OmVpZ2VuY29ycGxvdCgKICAgIG9ial9wY2EsCiAgICBjb21wb25lbnRzID0gUENBdG9vbHM6OmdldENvbXBvbmVudHMob2JqX3BjYSwgMTpsZW5ndGgob2JqX3BjYSRsb2FkaW5ncykpLAogICAgIyBtZXRhdmFycyA9IGMoInN0cmFpbiIsICJzdGF0ZSIsICJ0aW1lIiwgInJlcGxpY2F0ZSIsICJ0ZWNobmljYWwiKSwKICAgIG1ldGF2YXJzID0gYygic3RyYWluIiwgInJlcGxpY2F0ZSIsICJ0ZWNobmljYWwiKSwKICAgICMgbWV0YXZhcnMgPSBjKCJzdHJhaW4iLCAicmVwbGljYXRlIiwgInNhbXBsZV9uYW1lIiksCiAgICBjb2wgPSBjKCIjNzg1RUYwNzUiLCAiI0ZGRkZGRjc1IiwgIiNGRTYxMDA3NSIpLAogICAgc2NhbGUgPSBGQUxTRSwKICAgIGNvckZVTiA9ICJwZWFyc29uIiwKICAgIGNvck11bHRpcGxlVGVzdENvcnJlY3Rpb24gPSAiQkgiLAogICAgcGxvdFJzcXVhcmVkID0gVFJVRSwKICAgIGNvbEZyYW1lID0gIiNGRkZGRkYiLAogICAgbWFpbiA9IGJxdW90ZShQZWFyc29uIH4gcl4yIH4gY29ycmVsYXRlcyksCiAgICAjIG1haW4gPSAiUEMgUGVhcnNvbiByLXNxdWFyZWQgY29ycmVsYXRlcyIsCiAgICBmb250TWFpbiA9IDEsCiAgICB0aXRsZVggPSAiUHJpbmNpcGFsIGNvbXBvbmVudHMiLAogICAgZm9udFRpdGxlWCA9IDEsCiAgICBmb250TGFiWCA9IDEsCiAgICB0aXRsZVkgPSAiTW9kZWwgdmFyaWFibGVzIiwKICAgIHJvdFRpdGxlWSA9IDkwLAogICAgZm9udFRpdGxlWSA9IDEsCiAgICBmb250TGFiWSA9IDEKKQpQQ19jb3IKCgojICBHZXQgbGlzdHMgb2YgdG9wIGxvYWRpbmdzIGZvciBHTyBhbmFseXNlcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgZm9yKGkgaW4gYygiUEMxIiwgIlBDMiIsICJQQzMiLCAiUEM0IikpIHsKZm9yKGkgaW4gYygiUEMxIiwgIlBDMiIpKSB7CiAgICAjVE9ETyBXcml0ZSByZXN1bHRzIHRvIGxpc3Qgc28gdGhhdCBJIG9ubHkgbmVlZCB0byBxdWVyeSBhIHNpbmdsZSBvYmplY3QKICAgICMgaSA8LSAiUEMxIgogICAgIyAgUG9zaXRpdmUKICAgIGxvYWRpbmdzX3Bvc19QQyA8LSByb3duYW1lcyh0b3BfbG9hZGluZ3NfcG9zW1tpXV0pWzE6NTAwXQogICAgc2F2ZV90aXRsZV9wb3NfUEMgPC0gcGFzdGUwKAogICAgICAgICJ0b3AtNTAwLiIsCiAgICAgICAgc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKGdldF9uYW1lX29mX3Zhcihsb2FkaW5nc19wb3NfUEMpLCAiXyIsICItIiksCiAgICAgICAgIi4iLCBpLCAiLnR4dCIKICAgICkKICAgICMgcmVhZHI6OndyaXRlX3RzdigKICAgICMgICAgIGRwbHlyOjphc190aWJibGUobG9hZGluZ3NfcG9zX1BDKSwKICAgICMgICAgIHBhc3RlMChhcmdzJGRpcmVjdG9yeV9vdXQsICIvIiwgc2F2ZV90aXRsZV9wb3NfUEMpLAogICAgIyAgICAgY29sX25hbWVzID0gRkFMU0UKICAgICMgKQogICAgI1RPRE8gV29yayB1cCBzb21lIGxvZ2ljIGZvciBsb2NhdGlvbihzKSBmb3Igb3V0ZmlsZXMKICAgIAogICAgIyAgTmVnYXRpdmUKICAgIGxvYWRpbmdzX25lZ19QQyA8LSByb3duYW1lcyh0b3BfbG9hZGluZ3NfbmVnW1tpXV0pWzE6NTAwXQogICAgc2F2ZV90aXRsZV9uZWdfUEMgPC0gcGFzdGUwKAogICAgICAgICJ0b3AtNTAwLiIsCiAgICAgICAgc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKGdldF9uYW1lX29mX3Zhcihsb2FkaW5nc19uZWdfUEMpLCAiXyIsICItIiksCiAgICAgICAgIi4iLCBpLCAiLnR4dCIKICAgICkKICAgICMgcmVhZHI6OndyaXRlX3RzdigKICAgICMgICAgIGRwbHlyOjphc190aWJibGUobG9hZGluZ3NfbmVnX1BDKSwKICAgICMgICAgIHBhc3RlMChhcmdzJGRpcmVjdG9yeV9vdXQsICIvIiwgc2F2ZV90aXRsZV9uZWdfUEMpLAogICAgIyAgICAgY29sX25hbWVzID0gRkFMU0UKICAgICMgKQogICAgI1RPRE8gV29yayB1cCBzb21lIGxvZ2ljIGZvciBsb2NhdGlvbihzKSBmb3Igb3V0ZmlsZXMKfQpgYGAKPGJyIC8+CjxiciAvPgoKYCNIRVJFYAojIyBJSS4gUnVuIHBhaXJ3aXNlIGFuYWx5c2VzCmBgYHtyIFJ1biBwYWlyd2lzZSBhbmFseXNlcywgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0V9CmRhdGFzZXRzX3IxX3I2IDwtIGMoCiAgICAicjEtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSIsCiAgICAicjEtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIsCiAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSIsCiAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMiIsCiAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIKKQpkYXRhc2V0c19XVF9yNiA8LSBjKAogICAgIldUX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIiwKICAgICJXVF9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIsCiAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMSIsCiAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMV90ZWNoMiIsCiAgICAicjYtbl9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIKKQpkYXRhc2V0c19XVF9yMSA8LSBjKAogICAgInIxLW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDFfdGVjaDEiLAogICAgInIxLW5fUV9kYXk4X3Rjbl9TU19hdXgtRl90Yy1GX3JlcDJfdGVjaDEiLAogICAgIldUX1FfZGF5OF90Y25fU1NfYXV4LUZfdGMtRl9yZXAxX3RlY2gxIiwKICAgICJXVF9RX2RheThfdGNuX1NTX2F1eC1GX3RjLUZfcmVwMl90ZWNoMSIKKQoKIyAgTWFrZSBhIG5hbWVkIGxpc3QKZGF0YXNldHNfZ3JvdXBlZCA8LSBsaXN0KAogICAgImRhdGFzZXRzX3IxX3I2IiA9IGRhdGFzZXRzX3IxX3I2LAogICAgImRhdGFzZXRzX1dUX3I2IiA9IGRhdGFzZXRzX1dUX3I2LAogICAgImRhdGFzZXRzX1dUX3IxIiA9IGRhdGFzZXRzX1dUX3IxCikKCiNURVNUCmZvciAoaSBpbiAxOmxlbmd0aChkYXRhc2V0c19ncm91cGVkKSkgewogICAgIyBpIDwtIDEKICAgIHByaW50KG5hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV0pCiAgICBwcmludChkYXRhc2V0c19ncm91cGVkW1tpXV0pCiAgICBjYXQoIlxuIikKfQoKcmVzIDwtIGxpc3QoKQpmb3IgKGkgaW4gMTpsZW5ndGgoZGF0YXNldHNfZ3JvdXBlZCkpIHsKICAgICMgaSA8LSAxCiAgICBjYXQocGFzdGUwKAogICAgICAgICIjICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuIiwKICAgICAgICAiIyAgV29ya2luZyB3aXRoICciLAogICAgICAgIG5hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV0sCiAgICAgICAgIicgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiIsCiAgICAgICAgIiMgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiIKICAgICkpCiAgICAKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dIDwtIGxpc3QoKQogICAgCiAgICAjICAwIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KCIjKyAwLiBEYXRhc2V0cyBhcmUuLi5cblxuIikKICAgIHByaW50KGRhdGFzZXRzX2dyb3VwZWRbW2ldXSkKICAgIGNhdCgiXG4iKQogICAgCiAgICAjICBJbml0aWFsaXplIHZhcmlhYmxlICdkYXRhc2V0cycKICAgIGRhdGFzZXRzIDwtIGRhdGFzZXRzX2dyb3VwZWRbW2ldXQogICAgCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wMF9kYXRhc2V0cyJdXSA8LSBkYXRhc2V0cwogICAgCiAgICAjICAxIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgMS4gQ3JlYXRpbmcgJ2NvdW50c19kYXRhJyBtYXRyaXggZm9yICciLAogICAgICAgIG5hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV0sCiAgICAgICAgIidcblxuIgogICAgKSkKICAgIGNvdW50c19kYXRhIDwtIHRfZmNbLCBjb2xuYW1lcyh0X2ZjKSAlaW4lIGRhdGFzZXRzXSAlPiUKICAgICAgICBhcy5kYXRhLmZyYW1lKCkKICAgIAogICAgIyBjYXQoIkhvdyBkbyB0aGluZ3MgbG9vaz9cbiIpCiAgICAjIHByaW50KGhlYWQoZGF0YXNldHMpKQogICAgIyBjYXQoIlxuIikKICAgIAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDFfY291bnRzX2RhdGEiXV0gPC0gY291bnRzX2RhdGEKICAgIAogICAgIyAgMiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIGNhdChwYXN0ZTAoCiAgICAgICAgIiMrIDIuIElzb2xhdGUgZGF0YXNldHMgb2YgaW50ZXJlc3QgZm9yICciLAogICAgICAgIG5hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV0sCiAgICAgICAgIicgKCdjb2xfZGF0YScpXG5cbiIKICAgICkpCiAgICAKICAgIGNvbF9kYXRhIDwtIHNhbXBsZXNbc2FtcGxlcyRrZXlzICVpbiUgZGF0YXNldHMsIF0gJT4lCiAgICAgICAgYXMuZGF0YS5mcmFtZSgpICU+JSAgI0lNUE9SVEFOVCBPdXRwdXQgYSBkYXRhZnJhbWUsIG5vdCBhIHRpYmJsZQogICAgICAgIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKC4sIHZhciA9ICJrZXlzIikgJT4lICAjSU1QT1JUQU5UIEhhdmUgcm93IG5hbWVzCiAgICAgICAgZHJvcGxldmVscygpCiAgICAKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjAyX2NvbF9kYXRhIl1dIDwtIGNvbF9kYXRhCiAgICAKICAgICMgY2F0KCJIb3cgZG8gdGhpbmdzIGxvb2s/XG4iKQogICAgIyBwcmludChoZWFkKGNvbF9kYXRhKSkKICAgICMgY2F0KCJcbiIpCiAgICAKICAgICMgIDMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBjYXQocGFzdGUwKAogICAgICAgICIjKyAzLiBBc3NpZ24gbW9kZWwgbnVtZXJhdG9ycywgZGVub21pbmF0b3JzIGZvciAnIiwKICAgICAgICBuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dLAogICAgICAgICInXG5cbiIKICAgICkpCiAgICAKICAgIHdoYXRfY29tYm9zIDwtIGxpc3QoCiAgICAgICAgInIxLW5fcjYtbiIgPSBjKCJyMS1uIiwgInI2LW4iKSwKICAgICAgICAiV1RfcjEtbiIgPSBjKCJXVCIsICJyMS1uIiksCiAgICAgICAgIldUX3I2LW4iID0gYygiV1QiLCAicjYtbiIpCiAgICApCiAgICB3aGF0X2xldmVscyA8LSBjb2xfZGF0YSRzdHJhaW4gJT4lIGFzLmZhY3RvcigpICU+JSBsZXZlbHMoKQogICAgIyBzYW1wbGVzJHN0cmFpbiAlPiUgYXMuZmFjdG9yKCkgJT4lIGxldmVscygpCiAgICAKICAgICMgIExvZ2ljIHRvIGNhcmVmdWxseSwgY29ycmVjdGx5IGFzc2lnbiBtb2RlbCBudW1lcmF0b3JzLCBkZW5vbWluYXRvcnMKICAgIGlmKAogICAgICAgIHdoYXRfbGV2ZWxzICVpbiUgd2hhdF9jb21ib3NbWyJyMS1uX3I2LW4iXV0gJT4lCiAgICAgICAgICAgIGFsbCgpICU+JQogICAgICAgICAgICBpc1RSVUUoKQogICAgKSB7CiAgICAgICAgbW9kZWxfbiA8LSAicjYtbiIKICAgICAgICBtb2RlbF9kIDwtICJyMS1uIgogICAgICAgIGNvbF9kYXRhJHN0cmFpbiA8LSBmYWN0b3IoCiAgICAgICAgICAgIGNvbF9kYXRhJHN0cmFpbiwgbGV2ZWxzID0gYyhtb2RlbF9kLCBtb2RlbF9uKQogICAgICAgICkKICAgICAgICBtb2RlbF9zdHJpbmcgPC0gcGFzdGUobGV2ZWxzKGNvbF9kYXRhJHN0cmFpbiksIGNvbGxhcHNlID0gIiAiKQogICAgICAgIG1vZGVsX2xpbmVhciA8LSAifiB0ZWNobmljYWwgKyBzdHJhaW4iCiAgICB9IGVsc2UgaWYoCiAgICAgICAgd2hhdF9sZXZlbHMgJWluJSB3aGF0X2NvbWJvc1tbIldUX3IxLW4iXV0gJT4lCiAgICAgICAgICAgIGFsbCgpICU+JQogICAgICAgICAgICBpc1RSVUUoKQogICAgKSB7CiAgICAgICAgbW9kZWxfbiA8LSAicjEtbiIKICAgICAgICBtb2RlbF9kIDwtICJXVCIKICAgICAgICBjb2xfZGF0YSRzdHJhaW4gPC0gZmFjdG9yKAogICAgICAgICAgICBjb2xfZGF0YSRzdHJhaW4sIGxldmVscyA9IGMobW9kZWxfZCwgbW9kZWxfbikKICAgICAgICApCiAgICAgICAgbW9kZWxfc3RyaW5nIDwtIHBhc3RlKGxldmVscyhjb2xfZGF0YSRzdHJhaW4pLCBjb2xsYXBzZSA9ICIgIikKICAgICAgICBtb2RlbF9saW5lYXIgPC0gIn4gc3RyYWluIgogICAgfSBlbHNlIGlmKAogICAgICAgIHdoYXRfbGV2ZWxzICVpbiUgd2hhdF9jb21ib3NbWyJXVF9yNi1uIl1dICU+JQogICAgICAgICAgICBhbGwoKSAlPiUKICAgICAgICAgICAgaXNUUlVFKCkKICAgICkgewogICAgICAgIG1vZGVsX24gPC0gInI2LW4iCiAgICAgICAgbW9kZWxfZCA8LSAiV1QiCiAgICAgICAgY29sX2RhdGEkc3RyYWluIDwtIGZhY3RvcigKICAgICAgICAgICAgY29sX2RhdGEkc3RyYWluLCBsZXZlbHMgPSBjKG1vZGVsX2QsIG1vZGVsX24pCiAgICAgICAgKQogICAgICAgIG1vZGVsX3N0cmluZyA8LSBwYXN0ZShsZXZlbHMoY29sX2RhdGEkc3RyYWluKSwgY29sbGFwc2UgPSAiICIpCiAgICAgICAgbW9kZWxfbGluZWFyIDwtICJ+IHRlY2huaWNhbCArIHN0cmFpbiIKICAgIH0KICAgIAogICAgY2F0KHBhc3RlMCgKICAgICAgICAiICAgICAgIG51bWVyYXRvciAgIiwgbW9kZWxfbiwgIlxuIiwKICAgICAgICAiICAgICBkZW5vbWluYXRvciAgIiwgbW9kZWxfZCwgIlxuIiwKICAgICAgICAiICAgICBsZXZlbC1vcmRlciAgIiwgbW9kZWxfc3RyaW5nLCAiXG4iLAogICAgICAgICIgICAgbW9kZWwtbGluZWFyICAiLCBtb2RlbF9saW5lYXIsICJcblxuIgogICAgKSkKICAgIAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDNfbW9kZWxfbiJdXSA8LSBtb2RlbF9uCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wM19tb2RlbF9kIl1dIDwtIG1vZGVsX2QKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjAzX21vZGVsX3N0cmluZyJdXSA8LSBtb2RlbF9zdHJpbmcKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjAzX21vZGVsX2xpbmVhciJdXSA8LSBtb2RlbF9zdHJpbmcKICAgIAogICAgIyAgNCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIGNhdChwYXN0ZTAoCiAgICAgICAgIiMrIDQuIFBlcmZvcm0gZmFjdG9yLXRvLWludGVnZXIgY29udmVyc2lvbnMgZm9yICciLAogICAgICAgIG5hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV0sCiAgICAgICAgIicgdmFyaWFibGVzICdzdHJhaW4nLCAncmVwbGljYXRlJywgYW5kICd0ZWNobmljYWwnIChpLmUuLCBiYXRjaClcblxuIgogICAgKSkKICAgIAogICAgI1RPRE8gSSB0aGluayB0aGlzIGlzIGZpbmU7IGhvd2V2ZXIsIGlmIG5vdCwgdGhlbiBhZGQgaWYvZWxzZSBsb2dpYyAKICAgIGNvbF9kYXRhJG5vX3N0cmFpbiA8LSBzYXBwbHkoCiAgICAgICAgYXMuY2hhcmFjdGVyKGNvbF9kYXRhJHN0cmFpbiksCiAgICAgICAgc3dpdGNoLAogICAgICAgICJXVCIgPSAxLAogICAgICAgICJyMS1uIiA9IDIsCiAgICAgICAgInI2LW4iID0gMywKICAgICAgICBVU0UuTkFNRVMgPSBGQUxTRQogICAgKQogICAgY29sX2RhdGEkbm9fcmVwbGljYXRlIDwtIHNhcHBseSgKICAgICAgICBhcy5jaGFyYWN0ZXIoY29sX2RhdGEkcmVwbGljYXRlKSwKICAgICAgICBzd2l0Y2gsCiAgICAgICAgInJlcDEiID0gMSwKICAgICAgICAicmVwMiIgPSAyLAogICAgICAgIFVTRS5OQU1FUyA9IEZBTFNFCiAgICApCiAgICBjb2xfZGF0YSRub190ZWNobmljYWwgPC0gc2FwcGx5KAogICAgICAgIGFzLmNoYXJhY3Rlcihjb2xfZGF0YSR0ZWNobmljYWwpLAogICAgICAgIHN3aXRjaCwKICAgICAgICAidGVjaDEiID0gMSwKICAgICAgICAidGVjaDIiID0gMiwKICAgICAgICBVU0UuTkFNRVMgPSBGQUxTRQogICAgKQogICAgCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNF9jb2xfZGF0YSJdXSA8LSBjb2xfZGF0YQogICAgCiAgICAjICA1IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgNS4gTWFrZSB0aGUgREVTZXFEYXRhU2V0IChkZHMpIG9iamVjdCBmb3IgJyIsCiAgICAgICAgbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXSwKICAgICAgICAiJ1xuXG4iCiAgICApKQogICAgCiAgICBkZHMgPC0gREVTZXEyOjpERVNlcURhdGFTZXRGcm9tTWF0cml4KAogICAgICAgIGNvdW50RGF0YSA9IGNvdW50c19kYXRhLAogICAgICAgIGNvbERhdGEgPSBjb2xfZGF0YSwKICAgICAgICBkZXNpZ24gPSBhcy5mb3JtdWxhKGV2YWwobW9kZWxfbGluZWFyKSksCiAgICAgICAgcm93UmFuZ2VzID0gcG9zX2luZm8KICAgICkKICAgIAogICAgZGVzaWduIDwtIGRkc0BkZXNpZ24KICAgIAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDVfZGRzIl1dIDwtIGRkcwogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDVfZGVzaWduIl1dIDwtIGRlc2lnbgogICAgCiAgICBybShkZXNpZ24pCiAgICAKICAgICMgIDYgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBjYXQocGFzdGUwKAogICAgICAgICIjKyA2LiBSdW4gREUgYW5hbHlzZXMgZm9yICciLCBuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dLAogICAgICAgICInLCBleGFtaW5pbmcgUy4gY2VyZXZpc2lhZSBmZWF0dXJlcyBhbmQgIiwKICAgICAgICAidXNpbmcgUy4gY2VyZXZpc2lhZSBmZWF0dXJlcyBmb3Igc2l6ZS1mYWN0b3IgZXN0aW1hdGlvblxuXG4iCiAgICApKQogICAgCiAgICAjICA2YSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgNmEuIFBlcmZvcm0gc2l6ZS1mYWN0b3IgZXN0aW1hdGlvblxuXG4iCiAgICApKQogICAgCiAgICBkZHNfU0MgPC0gQmlvY0dlbmVyaWNzOjplc3RpbWF0ZVNpemVGYWN0b3JzKAogICAgICAgIGRkc1tkZHNAcm93UmFuZ2VzJGdlbm9tZSAhPSAiS19sYWN0aXMiLCBdCiAgICApCiAgICAjIGRkc19TQ0Bjb2xEYXRhCiAgICAKICAgICNUT0RPIFByaW50IGFuZCBzYXZlIHNvbWUgYnJpZWYgdGFibGUgb2Ygc2FtcGxlIGFuZCBzaXplIGZhY3RvcgogICAgc2Zfc2FtcGxlcyA8LSBkZHNfU0Mkc2l6ZUZhY3RvciAlPiUgbmFtZXMoKSAlPiUgdGliYmxlOjphc190aWJibGUoKQogICAgc2ZfdmFsdWVzIDwtIGRkc19TQyRzaXplRmFjdG9yICU+JSB0aWJibGU6OmFzX3RpYmJsZSgpCiAgICBzZl90YmxfU0MgPC0gZHBseXI6OmJpbmRfY29scyhzZl9zYW1wbGVzLCBzZl92YWx1ZXMpCiAgICBjb2xuYW1lcyhzZl90YmxfU0MpIDwtIGMoInNhbXBsZXMiLCAic2l6ZV9mYWN0b3JzIikKICAgIHJtKHNmX3NhbXBsZXMsIHNmX3ZhbHVlcykKICAgIAogICAgIyBwcmludChzZl90YmxfU0MsIG4gPSBucm93KHNmX3RibF9TQykpCiAgICAKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA2YV9kZHNfU0MiXV0gPC0gZGRzX1NDCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNmFfc2ZfdGJsX1NDIl1dIDwtIHNmX3RibF9TQwogICAgCiAgICAjICA2YiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgNmIuIENhbGwgREVTZXEyIHVzaW5nIGRlZmF1bHQgcGFyYW1ldGVyc1xuXG4iCiAgICApKQogICAgCiAgICBkZHNfU0MgPC0gREVTZXEyOjpERVNlcShkZHNfU0MpCiAgICAKICAgICMgIENoZWNrIG1vZGVsIGluZm9ybWF0aW9uCiAgICBjYXQocGFzdGUwKAogICAgICAgICJERVNlcTIgbW9kZWwgaW5mb3JtYXRpb246ICciLCBERVNlcTI6OnJlc3VsdHNOYW1lcyhkZHNfU0MpWzJdLCAiJ1xuXG4iLAogICAgICAgICJUaHVzLCB0aGUgbW9kZWwgdmFyaWVzIG9uIHN0cmFpbiwgdGhlIGxlZnQgc2FtcGxlIGlzIHRoZSBudW1lcmF0b3IsICIsCiAgICAgICAgInRoZSByaWdodCBzYW1wbGUgaXMgdGhlIGRlbm9taW5hdG9yXG4iLAogICAgICAgICIgICAgLSBOdW1lcmF0b3I6IHRvcCBpbiBNQSBwbG90cywgcmlnaHQgaW4gdm9sY2FubyBwbG90c1xuIiwKICAgICAgICAiICAgIC0gRGVub21pbmF0b3I6IGJvdHRvbSBpbiBNQSBwbG90cywgbGVmdCBpbiB2b2xjYW5vIHBsb3RzXG5cbiIKICAgICkpCgogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDZiX2Rkc19TQyJdXSA8LSBkZHNfU0MKICAgIAogICAgIyAgNmMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIGNhdChwYXN0ZTAoCiAgICAgICAgIiMrIDZjLiBDYWxsIERFU2VxMjo6cmVzdWx0cygpXG5cbiIKICAgICkpCiAgICAKICAgICMgIFNldCB1cCBuZWNlc3NhcnkgcGFyYW1ldGVycyBmb3IgZ2VuZXJhdGlvbiBvZiBERVNlcTIgcmVzdWx0cyB0YWJsZQogICAgaW5kZXBlbmRlbnRfZmlsdGVyaW5nIDwtIFRSVUUKICAgIHRocmVzaG9sZF9wIDwtIDAuMDUKICAgIHRocmVzaG9sZF9sZmMgPC0gMAogICAgCiAgICBjYXQocGFzdGUwKAogICAgICAgICIgICAgaW5kZXBlbmRlbnRfZmlsdGVyaW5nICAiLCBpbmRlcGVuZGVudF9maWx0ZXJpbmcsICJcbiIsCiAgICAgICAgIiAgICAgICAgICAgICAgdGhyZXNob2xkX3AgICIsIHRocmVzaG9sZF9wLCAiXG4iLAogICAgICAgICIgICAgICAgICAgICB0aHJlc2hvbGRfbGZjICAiLCB0aHJlc2hvbGRfbGZjLCAiXG5cbiIKICAgICkpCiAgICAKICAgICMgIE91dHB1dCBhIERFU2VxMiBEYXRhRnJhbWUgb2JqZWN0CiAgICBER0VfdW5zaHJ1bmtlbl9ERl9TQyA8LSBERVNlcTI6OnJlc3VsdHMoCiAgICAgICAgZGRzX1NDLAogICAgICAgIG5hbWUgPSBERVNlcTI6OnJlc3VsdHNOYW1lcyhkZHNfU0MpWzJdLAogICAgICAgIGluZGVwZW5kZW50RmlsdGVyaW5nID0gaW5kZXBlbmRlbnRfZmlsdGVyaW5nLAogICAgICAgIGFscGhhID0gdGhyZXNob2xkX3AsCiAgICAgICAgbGZjVGhyZXNob2xkID0gdGhyZXNob2xkX2xmYywKICAgICAgICBmb3JtYXQgPSAiRGF0YUZyYW1lIgogICAgKQogICAgCiAgICAjICBPdXRwdXQgYSBHUmFuZ2VzIG9iamVjdCwgd2hpY2ggd2UgY2FuIGVhc2lseSBhZGQgdG8gYW5kIGNvbnZlcnQgdG8gb3RoZXIKICAgICMrIGZvcm1hdHMgKHN1Y2ggYXMgYSB0aWJibGUpCiAgICBER0VfdW5zaHJ1bmtlbl9HUl9TQyA8LSBERVNlcTI6OnJlc3VsdHMoCiAgICAgICAgZGRzX1NDLAogICAgICAgIG5hbWUgPSBERVNlcTI6OnJlc3VsdHNOYW1lcyhkZHNfU0MpWzJdLAogICAgICAgIGluZGVwZW5kZW50RmlsdGVyaW5nID0gaW5kZXBlbmRlbnRfZmlsdGVyaW5nLAogICAgICAgIGFscGhhID0gdGhyZXNob2xkX3AsCiAgICAgICAgbGZjVGhyZXNob2xkID0gdGhyZXNob2xkX2xmYywKICAgICAgICBmb3JtYXQgPSAiR1JhbmdlcyIKICAgICkKICAgIERHRV91bnNocnVua2VuX0dSX1NDJGxlbmd0aCA8LSBNYXRyaXhHZW5lcmljczo6cm93UmFuZ2VzKAogICAgICAgIGRkc19TQwogICAgKSRsZW5ndGgKICAgIERHRV91bnNocnVua2VuX0dSX1NDJGZlYXR1cmUgPC0gTWF0cml4R2VuZXJpY3M6OnJvd1JhbmdlcygKICAgICAgICBkZHNfU0MKICAgICkkZmVhdHVyZQogICAgREdFX3Vuc2hydW5rZW5fR1JfU0MkZmVhdHVyZV9pbml0IDwtIE1hdHJpeEdlbmVyaWNzOjpyb3dSYW5nZXMoCiAgICAgICAgZGRzX1NDCiAgICApJGZlYXR1cmVfaW5pdAogICAgREdFX3Vuc2hydW5rZW5fR1JfU0MkdHlwZSA8LSBNYXRyaXhHZW5lcmljczo6cm93UmFuZ2VzKAogICAgICAgIGRkc19TQwogICAgKSR0eXBlCiAgICBER0VfdW5zaHJ1bmtlbl9HUl9TQyRnZW5vbWUgPC0gTWF0cml4R2VuZXJpY3M6OnJvd1JhbmdlcygKICAgICAgICBkZHNfU0MKICAgICkkZ2Vub21lCiAgICAKICAgIHRfREdFX1NDIDwtIERHRV91bnNocnVua2VuX0dSX1NDICU+JQogICAgICAgIGRwbHlyOjphc190aWJibGUoKSAlPiUKICAgICAgICBkcGx5cjo6cmVuYW1lKGNociA9IHNlcW5hbWVzKQogICAgCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNmNfaW5kZXBlbmRlbnRfZmlsdGVyaW5nIl1dIDwtIGluZGVwZW5kZW50X2ZpbHRlcmluZwogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDZjX3RocmVzaG9sZF9wIl1dIDwtIHRocmVzaG9sZF9wCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNmNfdGhyZXNob2xkX2xmYyJdXSA8LSB0aHJlc2hvbGRfbGZjCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNmNfREdFX3Vuc2hydW5rZW5fREZfU0MiXV0gPC0gREdFX3Vuc2hydW5rZW5fREZfU0MKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA2Y19ER0VfdW5zaHJ1bmtlbl9HUl9TQyJdXSA8LSBER0VfdW5zaHJ1bmtlbl9HUl9TQwogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDZjX3RfREdFX1NDIl1dIDwtIHRfREdFX1NDCiAgICAKICAgIHJtKGluZGVwZW5kZW50X2ZpbHRlcmluZywgdGhyZXNob2xkX3AsIHRocmVzaG9sZF9sZmMpCiAgICAKICAgICMgIDZkIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBjYXQocGFzdGUwKAogICAgICAgICIjKyA2ZC4gTWFrZSBhbiBNQSBwbG90IHRoYXQgY29sb3JzIGZlYXR1cmVzIGJ5ICIsCiAgICAgICAgImluZGVwZW5kZW50IGZpbHRlcmluZ1xuXG4iCiAgICApKQogICAgCiAgICAjICBTZXQgdXAgdGVtcG9yYXJ5IHZhcmlhYmxlICd0YmwnLCB3aGljaCB3aWxsIGJlIHBhc3NlZCB0byBnZ3Bsb3QKICAgIHRibCA8LSB0X0RHRV9TQwogICAgdGJsIDwtIHRibFt3aXRoKHRibCwgb3JkZXIobG9nMkZvbGRDaGFuZ2UpKSwgXQogICAgdGJsJHRocmVzaG9sZCA8LSBhcy5mYWN0b3IodGJsJHBhZGogPD0gMC4wNSkKICAgIHRibCRsb2cxMGJhc2VNZWFuIDwtIGlmZWxzZSgKICAgICAgICBpcy5pbmZpbml0ZShsb2cxMCh0YmwkYmFzZU1lYW4pKSwgTkEsIGxvZzEwKHRibCRiYXNlTWVhbikKICAgICkKICAgIAogICAgdGl0bGUgPC0gcGFzdGUwKAogICAgICAgICJNQSBwbG90IHwgUy4gY2VyZXZpc2lhZSBmZWF0dXJlcyB8XG4iLAogICAgICAgICJzaXplIGZhY3RvcnMgZXN0aW1hdGVkIHdpdGggYWxsIFMuIGNlcmV2aXNpYWUgZmVhdHVyZXMiCiAgICApCiAgICBzdWJ0aXRsZSA8LSBwYXN0ZSgKICAgICAgICAicG9pbnRzOiBTLiBjZXJldmlzaWFlIGZlYXR1cmVzIiwKICAgICAgICAifCB0b3A6IHVwIGluIiwgbW9kZWxfbiwKICAgICAgICAifCBib3R0b206IHVwIGluIiwgbW9kZWxfZAogICAgKSAgIyBbMV0gInN0cmFpbl9vLmRfdnNfbjMuZCIKICAgIE1BX1NDIDwtIGdncGxvdCgKICAgICAgICB0YmwsIGFlcyh4ID0gbG9nMTBiYXNlTWVhbiwgeSA9IGxvZzJGb2xkQ2hhbmdlLCBjb2xvdXIgPSB0aHJlc2hvbGQpCiAgICApICsKICAgICAgICBnZW9tX3BvaW50KGFscGhhID0gMC4yNSwgc2l6ZSA9IDAuNSkgKwogICAgICAgICMgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDApLCBjb2xvdXIgPSAiIzAwMDAwMCIsIGxpbmV3aWR0aCA9IDAuMjUpICsKICAgICAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMCksIGNvbG91ciA9ICIjMDAwMDAwIiwgc2l6ZSA9IDAuMjUpICsKICAgICAgICAjIHlsaW0oYyhtaW4odGJsJGxvZzJGb2xkQ2hhbmdlKSwgbWF4KHRibCRsb2cyRm9sZENoYW5nZSkpKSArCiAgICAgICAgeWxpbShjKC0xNCwgMTQpKSArCiAgICAgICAgeGxhYigibG9nMTAobWVhbiBub3JtYWxpemVkIGNvdW50cykiKSArCiAgICAgICAgeWxhYigibG9nMihmb2xkIGNoYW5nZSkiKSArCiAgICAgICAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKG5hbWUgPSAicSDiiaQgMC4wNSIpICsKICAgICAgICBnZ3RpdGxlKHRpdGxlLCBzdWJ0aXRsZSkgKwogICAgICAgIHRoZW1lX3NsaWNrCiAgICBNQV9TQwogICAgI1RPRE8gMS8yIEV4cGxhaW4gYW5kIG1ha2UgYSBkZWNpc2lvbiByZWdhcmRpbmcgdXNlIG9mICdzaXplJyBvciAnbGluZXdpZHRoJwogICAgI1RPRE8gMi8yIHBhcmFtZXRlcnMKICAgIAogICAgIyAgQ3JlYXRlIGEgdmVjdG9yIG9mIGZlYXR1cmVzIHRoYXQgYm90aCBwYXNzZWQgaW5kZXBlbmRlbnQgZmlsdGVyaW5nIChhbmQgdGh1cwogICAgIysgaGF2ZSBhbiBpbmhlcmVudGx5IGhpZ2ggbWVhbiBleHByZXNzaW9uKSBhbmQgYXJlIG5vdCBzdGF0aXN0aWNhbGx5CiAgICAjKyBzaWduaWZpY2FudDsgdGhpcyB2ZWN0b3Igc2lnbmlmaWVzIGZlYXR1cmVzIHRoYXQgYXJlICJzdGFibHkgZXhwcmVzc2VkIgogICAgIysgYmV0d2VlbiBjb25kaXRpb25zCiAgICB0Ymwkc3RhYmx5X2V4cHJlc3NlZCA8LSBpZmVsc2UoCiAgICAgICAgIWlzLm5hKHRibCR0aHJlc2hvbGQpICYgdGJsJHBhZGogPiAwLjA1LAogICAgICAgIFRSVUUsCiAgICAgICAgRkFMU0UKICAgICkKICAgIHN0YWJseV9leHByZXNzZWRfU0MgPC0gdGJsJGZlYXR1cmVbdGJsJHN0YWJseV9leHByZXNzZWQgPT0gVFJVRV0KICAgIAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDZkX3RibCJdXSA8LSB0YmwKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA2ZF90aXRsZSJdXSA8LSB0aXRsZQogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDZkX3N1YnRpdGxlIl1dIDwtIHN1YnRpdGxlCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNmRfTUFfU0MiXV0gPC0gTUFfU0MKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA2ZF9zdGFibHlfZXhwcmVzc2VkX1NDIl1dIDwtIHN0YWJseV9leHByZXNzZWRfU0MKICAgIAogICAgcm0odGJsLCB0aXRsZSwgc3VidGl0bGUpCiAgICAKICAgICMgIDZlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBjYXQocGFzdGUwKAogICAgICAgICIjKyA2ZS4gTWFrZSBhIHZvbGNhbm8gcGxvdFxuXG4iCiAgICApKQogICAgCiAgICAjICBJZGVudGlmeSBhbmQgaXNvbGF0ZSB0aGUgdG9wIDUgdXByZWd1bGF0ZWQgZmVhdHVyZXMgYW5kIHRoZSB0b3AgNSBkb3duLQogICAgIysgcmVndWxhdGVkIGZlYXR1cmVzCiAgICBhbGwgPC0gdF9ER0VfU0MkZmVhdHVyZQogICAgc2VsZWN0aW9uX2Rvd24gPC0gdF9ER0VfU0MgJT4lCiAgICAgICAgZHBseXI6OmZpbHRlcihsb2cyRm9sZENoYW5nZSA8IDApICU+JQogICAgICAgIGRwbHlyOjphcnJhbmdlKHBhZGopICU+JQogICAgICAgIGRwbHlyOjpzbGljZSgxOjUpCiAgICBzZWxlY3Rpb25fdXAgPC0gdF9ER0VfU0MgJT4lCiAgICAgICAgZHBseXI6OmZpbHRlcihsb2cyRm9sZENoYW5nZSA+IDApICU+JQogICAgICAgIGRwbHlyOjphcnJhbmdlKHBhZGopICU+JQogICAgICAgIGRwbHlyOjpzbGljZSgxOjUpCiAgICBzZWxlY3Rpb24gPC0gYyhzZWxlY3Rpb25fZG93bltbImZlYXR1cmUiXV0sIHNlbGVjdGlvbl91cFtbImZlYXR1cmUiXV0pICU+JQogICAgICAgICAgICBhcy5jaGFyYWN0ZXIoKQogICAgCiAgICB0aXRsZSA8LSBwYXN0ZTAoCiAgICAgICAgInZvbGNhbm8gcGxvdCB8IFMuIGNlcmV2aXNpYWUgZmVhdHVyZXMgfFxuIiwKICAgICAgICAic2l6ZSBmYWN0b3JzIGVzdGltYXRlZCB3aXRoIGFsbCBTLiBjZXJldmlzaWFlIGZlYXR1cmVzIgogICAgKQogICAgc3VidGl0bGUgPC0gcGFzdGUoCiAgICAgICAgInBvaW50czogUy4gY2VyZXZpc2lhZSBmZWF0dXJlcyIsCiAgICAgICAgInwgbGVmdDogdXAgaW4iLCBtb2RlbF9kLAogICAgICAgICJ8IHJpZ2h0OiB1cCBpbiIsIG1vZGVsX24sCiAgICAgICAgInxcbmxhYmVsczogdG9wIDUiLCBtb2RlbF9kLCAiYW5kIHRvcCA1IiwgbW9kZWxfbiwgImZlYXR1cmVzIgogICAgKSAgIyBbMV0gInN0cmFpbl9vLmRfdnNfbjMuZCIKICAgIHZvbGNhbm9fU0MgPC0gcGxvdF92b2xjYW5vKAogICAgICAgIHRhYmxlID0gdF9ER0VfU0MsCiAgICAgICAgbGFiZWwgPSBhbGwsCiAgICAgICAgc2VsZWN0aW9uID0gc2VsZWN0aW9uLAogICAgICAgIGxhYmVsX3NpemUgPSAyLjUsCiAgICAgICAgcF9jdXRvZmYgPSAwLjA1LAogICAgICAgIEZDX2N1dG9mZiA9IDEsCiAgICAgICAgeGxpbSA9IGMoLTE0LCAxNCksCiAgICAgICAgeWxpbSA9IGMoMCwgMTApLAogICAgICAgICMgeWxpbSA9IGMoMCwgMzEwKSwKICAgICAgICBjb2xvciA9ICIjNTJCRTlCIiwKICAgICAgICB0aXRsZSA9IHRpdGxlLAogICAgICAgIHN1YnRpdGxlID0gc3VidGl0bGUKICAgICkKICAgIHZvbGNhbm9fU0MKICAgICMgc2F2ZV92b2xjYW5vKAogICAgIyAgICAgZmlsZSA9ICJ0ZXN0LnBkZiIsCiAgICAjICAgICBwbG90ID0gcCwKICAgICMgICAgIHdpZHRoID0gMiwKICAgICMgICAgIGhlaWdodCA9IDMKICAgICMgKQogICAgCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNmVfYWxsIl1dIDwtIGFsbAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDZlX3NlbGVjdGlvbl9kb3duIl1dIDwtIHNlbGVjdGlvbl9kb3duCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNmVfc2VsZWN0aW9uX3VwIl1dIDwtIHNlbGVjdGlvbl91cAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDZlX3NlbGVjdGlvbiJdXSA8LSBzZWxlY3Rpb24KICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA2ZV90aXRsZSJdXSA8LSB0aXRsZQogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDZlX3N1YnRpdGxlIl1dIDwtIHN1YnRpdGxlCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wNmVfdm9sY2Fub19TQyJdXSA8LSB2b2xjYW5vX1NDCiAgICAKICAgIHJtKGFsbCwgc2VsZWN0aW9uLCBzZWxlY3Rpb25fdXAsIHNlbGVjdGlvbl9kb3duLCB0aXRsZSwgc3VidGl0bGUpCgogICAgIyAgNyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIGNhdChwYXN0ZTAoCiAgICAgICAgIiMrIDcuIFJ1biBERSBhbmFseXNlcyBmb3IgJyIsIG5hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV0sCiAgICAgICAgIicsIGV4YW1pbmluZyBLLiBsYWN0aXMgZmVhdHVyZXMgYW5kICIsCiAgICAgICAgInVzaW5nIEsuIGxhY3RpcyBmZWF0dXJlcyBmb3Igc2l6ZS1mYWN0b3IgZXN0aW1hdGlvblxuXG4iCiAgICApKQogICAgCiAgICAjICA3YSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgN2EuIFBlcmZvcm0gc2l6ZS1mYWN0b3IgZXN0aW1hdGlvblxuXG4iCiAgICApKQogICAgCiAgICBkZHNfS0wgPC0gQmlvY0dlbmVyaWNzOjplc3RpbWF0ZVNpemVGYWN0b3JzKAogICAgICAgIGRkc1tkZHNAcm93UmFuZ2VzJGdlbm9tZSAhPSAiU19jZXJldmlzaWFlIiwgXQogICAgKQogICAgIyBkZHNfS0xAY29sRGF0YQogICAgCiAgICAjVE9ETyBQcmludCBhbmQgc2F2ZSBzb21lIGJyaWVmIHRhYmxlIG9mIHNhbXBsZSBhbmQgc2l6ZSBmYWN0b3IKICAgIHNmX3NhbXBsZXMgPC0gZGRzX0tMJHNpemVGYWN0b3IgJT4lIG5hbWVzKCkgJT4lIHRpYmJsZTo6YXNfdGliYmxlKCkKICAgIHNmX3ZhbHVlcyA8LSBkZHNfS0wkc2l6ZUZhY3RvciAlPiUgdGliYmxlOjphc190aWJibGUoKQogICAgc2ZfdGJsX0tMIDwtIGRwbHlyOjpiaW5kX2NvbHMoc2Zfc2FtcGxlcywgc2ZfdmFsdWVzKQogICAgY29sbmFtZXMoc2ZfdGJsX0tMKSA8LSBjKCJzYW1wbGVzIiwgInNpemVfZmFjdG9ycyIpCiAgICBybShzZl9zYW1wbGVzLCBzZl92YWx1ZXMpCiAgICAKICAgICMgcHJpbnQoc2ZfdGJsX0tMLCBuID0gbnJvdyhzZl90YmxfS0wpKQogICAgCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wN2FfZGRzX0tMIl1dIDwtIGRkc19LTAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDdhX3NmX3RibF9LTCJdXSA8LSBzZl90YmxfS0wKICAgIAogICAgIyAgN2IgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIGNhdChwYXN0ZTAoCiAgICAgICAgIiMrIDdiLiBDYWxsIERFU2VxMiB1c2luZyBkZWZhdWx0IHBhcmFtZXRlcnNcblxuIgogICAgKSkKICAgIAogICAgZGRzX0tMIDwtIERFU2VxMjo6REVTZXEoZGRzX0tMKQogICAgCiAgICAjICBDaGVjayBtb2RlbCBpbmZvcm1hdGlvbgogICAgY2F0KHBhc3RlMCgKICAgICAgICAiREVTZXEyIG1vZGVsIGluZm9ybWF0aW9uOiAnIiwgREVTZXEyOjpyZXN1bHRzTmFtZXMoZGRzX0tMKVsyXSwgIidcblxuIiwKICAgICAgICAiVGh1cywgdGhlIG1vZGVsIHZhcmllcyBvbiBzdHJhaW4sIHRoZSBsZWZ0IHNhbXBsZSBpcyB0aGUgbnVtZXJhdG9yLCAiLAogICAgICAgICJ0aGUgcmlnaHQgc2FtcGxlIGlzIHRoZSBkZW5vbWluYXRvclxuIiwKICAgICAgICAiICAgIC0gTnVtZXJhdG9yOiB0b3AgaW4gTUEgcGxvdHMsIHJpZ2h0IGluIHZvbGNhbm8gcGxvdHNcbiIsCiAgICAgICAgIiAgICAtIERlbm9taW5hdG9yOiBib3R0b20gaW4gTUEgcGxvdHMsIGxlZnQgaW4gdm9sY2FubyBwbG90c1xuXG4iCiAgICApKQogICAgCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wN2JfZGRzX0tMIl1dIDwtIGRkc19LTAoKICAgICMgIDdjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBjYXQocGFzdGUwKAogICAgICAgICIjKyA3Yy4gQ2FsbCBERVNlcTI6OnJlc3VsdHMoKVxuXG4iCiAgICApKQogICAgCiAgICAjICBTZXQgdXAgbmVjZXNzYXJ5IHBhcmFtZXRlcnMgZm9yIGdlbmVyYXRpb24gb2YgREVTZXEyIHJlc3VsdHMgdGFibGUKICAgIGluZGVwZW5kZW50X2ZpbHRlcmluZyA8LSBUUlVFCiAgICB0aHJlc2hvbGRfcCA8LSAwLjA1CiAgICB0aHJlc2hvbGRfbGZjIDwtIDAKICAgIAogICAgY2F0KHBhc3RlMCgKICAgICAgICAiICAgIGluZGVwZW5kZW50X2ZpbHRlcmluZyAgIiwgaW5kZXBlbmRlbnRfZmlsdGVyaW5nLCAiXG4iLAogICAgICAgICIgICAgICAgICAgICAgIHRocmVzaG9sZF9wICAiLCB0aHJlc2hvbGRfcCwgIlxuIiwKICAgICAgICAiICAgICAgICAgICAgdGhyZXNob2xkX2xmYyAgIiwgdGhyZXNob2xkX2xmYywgIlxuXG4iCiAgICApKQogICAgCiAgICAjICBPdXRwdXQgYSBERVNlcTIgRGF0YUZyYW1lIG9iamVjdAogICAgREdFX3Vuc2hydW5rZW5fREZfS0wgPC0gREVTZXEyOjpyZXN1bHRzKAogICAgICAgIGRkc19LTCwKICAgICAgICBuYW1lID0gREVTZXEyOjpyZXN1bHRzTmFtZXMoZGRzX0tMKVsyXSwKICAgICAgICBpbmRlcGVuZGVudEZpbHRlcmluZyA9IGluZGVwZW5kZW50X2ZpbHRlcmluZywKICAgICAgICBhbHBoYSA9IHRocmVzaG9sZF9wLAogICAgICAgIGxmY1RocmVzaG9sZCA9IHRocmVzaG9sZF9sZmMsCiAgICAgICAgZm9ybWF0ID0gIkRhdGFGcmFtZSIKICAgICkKICAgIAogICAgIyAgT3V0cHV0IGEgR1JhbmdlcyBvYmplY3QsIHdoaWNoIHdlIGNhbiBlYXNpbHkgYWRkIHRvIGFuZCBjb252ZXJ0IHRvIG90aGVyCiAgICAjKyBmb3JtYXRzIChzdWNoIGFzIGEgdGliYmxlKQogICAgREdFX3Vuc2hydW5rZW5fR1JfS0wgPC0gREVTZXEyOjpyZXN1bHRzKAogICAgICAgIGRkc19LTCwKICAgICAgICBuYW1lID0gREVTZXEyOjpyZXN1bHRzTmFtZXMoZGRzX0tMKVsyXSwKICAgICAgICBpbmRlcGVuZGVudEZpbHRlcmluZyA9IGluZGVwZW5kZW50X2ZpbHRlcmluZywKICAgICAgICBhbHBoYSA9IHRocmVzaG9sZF9wLAogICAgICAgIGxmY1RocmVzaG9sZCA9IHRocmVzaG9sZF9sZmMsCiAgICAgICAgZm9ybWF0ID0gIkdSYW5nZXMiCiAgICApCiAgICBER0VfdW5zaHJ1bmtlbl9HUl9LTCRsZW5ndGggPC0gTWF0cml4R2VuZXJpY3M6OnJvd1JhbmdlcygKICAgICAgICBkZHNfS0wKICAgICkkbGVuZ3RoCiAgICBER0VfdW5zaHJ1bmtlbl9HUl9LTCRmZWF0dXJlIDwtIE1hdHJpeEdlbmVyaWNzOjpyb3dSYW5nZXMoCiAgICAgICAgZGRzX0tMCiAgICApJGZlYXR1cmUKICAgIERHRV91bnNocnVua2VuX0dSX0tMJGZlYXR1cmVfaW5pdCA8LSBNYXRyaXhHZW5lcmljczo6cm93UmFuZ2VzKAogICAgICAgIGRkc19LTAogICAgKSRmZWF0dXJlX2luaXQKICAgIERHRV91bnNocnVua2VuX0dSX0tMJHR5cGUgPC0gTWF0cml4R2VuZXJpY3M6OnJvd1JhbmdlcygKICAgICAgICBkZHNfS0wKICAgICkkdHlwZQogICAgREdFX3Vuc2hydW5rZW5fR1JfS0wkZ2Vub21lIDwtIE1hdHJpeEdlbmVyaWNzOjpyb3dSYW5nZXMoCiAgICAgICAgZGRzX0tMCiAgICApJGdlbm9tZQogICAgCiAgICB0X0RHRV9LTCA8LSBER0VfdW5zaHJ1bmtlbl9HUl9LTCAlPiUKICAgICAgICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lCiAgICAgICAgZHBseXI6OnJlbmFtZShjaHIgPSBzZXFuYW1lcykKICAgIAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDdjX2luZGVwZW5kZW50X2ZpbHRlcmluZyJdXSA8LSBpbmRlcGVuZGVudF9maWx0ZXJpbmcKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA3Y190aHJlc2hvbGRfcCJdXSA8LSB0aHJlc2hvbGRfcAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDdjX3RocmVzaG9sZF9sZmMiXV0gPC0gdGhyZXNob2xkX2xmYwogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDdjX0RHRV91bnNocnVua2VuX0RGX0tMIl1dIDwtIERHRV91bnNocnVua2VuX0RGX0tMCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wN2NfREdFX3Vuc2hydW5rZW5fR1JfS0wiXV0gPC0gREdFX3Vuc2hydW5rZW5fR1JfS0wKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA3Y190X0RHRV9LTCJdXSA8LSB0X0RHRV9LTAogICAgCiAgICBybShpbmRlcGVuZGVudF9maWx0ZXJpbmcsIHRocmVzaG9sZF9wLCB0aHJlc2hvbGRfbGZjKQogICAgCiAgICAjICA3ZCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgN2QuIE1ha2UgYW4gTUEgcGxvdCB0aGF0IGNvbG9ycyBmZWF0dXJlcyBieSAiLAogICAgICAgICJpbmRlcGVuZGVudCBmaWx0ZXJpbmdcblxuIgogICAgKSkKICAgIAogICAgIyAgU2V0IHVwIHRlbXBvcmFyeSB2YXJpYWJsZSAndGJsJywgd2hpY2ggd2lsbCBiZSBwYXNzZWQgdG8gZ2dwbG90CiAgICB0YmwgPC0gdF9ER0VfS0wKICAgIHRibCA8LSB0Ymxbd2l0aCh0YmwsIG9yZGVyKGxvZzJGb2xkQ2hhbmdlKSksIF0KICAgIHRibCR0aHJlc2hvbGQgPC0gYXMuZmFjdG9yKHRibCRwYWRqIDw9IDAuMDUpCiAgICB0YmwkbG9nMTBiYXNlTWVhbiA8LSBpZmVsc2UoCiAgICAgICAgaXMuaW5maW5pdGUobG9nMTAodGJsJGJhc2VNZWFuKSksIE5BLCBsb2cxMCh0YmwkYmFzZU1lYW4pCiAgICApCiAgICAKICAgIHRpdGxlIDwtIHBhc3RlMCgKICAgICAgICAiTUEgcGxvdCB8IEsuIGxhY3RpcyBmZWF0dXJlcyB8XG4iLAogICAgICAgICJzaXplIGZhY3RvcnMgZXN0aW1hdGVkIHdpdGggYWxsIEsuIGxhY3RpcyBmZWF0dXJlcyIKICAgICkKICAgIHN1YnRpdGxlIDwtIHBhc3RlKAogICAgICAgICJwb2ludHM6IEsuIGxhY3RpcyBmZWF0dXJlcyIsCiAgICAgICAgInwgdG9wOiB1cCBpbiIsIG1vZGVsX24sCiAgICAgICAgInwgYm90dG9tOiB1cCBpbiIsIG1vZGVsX2QKICAgICkgICMgWzFdICJzdHJhaW5fby5kX3ZzX24zLmQiCiAgICBNQV9LTCA8LSBnZ3Bsb3QoCiAgICAgICAgdGJsLCBhZXMoeCA9IGxvZzEwYmFzZU1lYW4sIHkgPSBsb2cyRm9sZENoYW5nZSwgY29sb3VyID0gdGhyZXNob2xkKQogICAgKSArCiAgICAgICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMjUsIHNpemUgPSAwLjUpICsKICAgICAgICAjIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAwKSwgY29sb3VyID0gIiMwMDAwMDAiLCBsaW5ld2lkdGggPSAwLjI1KSArCiAgICAgICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDApLCBjb2xvdXIgPSAiIzAwMDAwMCIsIHNpemUgPSAwLjI1KSArCiAgICAgICAgIyB5bGltKGMobWluKHRibCRsb2cyRm9sZENoYW5nZSksIG1heCh0YmwkbG9nMkZvbGRDaGFuZ2UpKSkgKwogICAgICAgIHlsaW0oYygtMTQsIDE0KSkgKwogICAgICAgIHhsYWIoImxvZzEwKG1lYW4gbm9ybWFsaXplZCBjb3VudHMpIikgKwogICAgICAgIHlsYWIoImxvZzIoZm9sZCBjaGFuZ2UpIikgKwogICAgICAgIHNjYWxlX2NvbG91cl9kaXNjcmV0ZShuYW1lID0gInEg4omkIDAuMDUiKSArCiAgICAgICAgZ2d0aXRsZSh0aXRsZSwgc3VidGl0bGUpICsKICAgICAgICB0aGVtZV9zbGljawogICAgTUFfS0wKICAgICNUT0RPIDEvMiBFeHBsYWluIGFuZCBtYWtlIGEgZGVjaXNpb24gcmVnYXJkaW5nIHVzZSBvZiAnc2l6ZScgb3IgJ2xpbmV3aWR0aCcKICAgICNUT0RPIDIvMiBwYXJhbWV0ZXJzCiAgICAKICAgICMgIENyZWF0ZSBhIHZlY3RvciBvZiBmZWF0dXJlcyB0aGF0IGJvdGggcGFzc2VkIGluZGVwZW5kZW50IGZpbHRlcmluZyAoYW5kIHRodXMKICAgICMrIGhhdmUgYW4gaW5oZXJlbnRseSBoaWdoIG1lYW4gZXhwcmVzc2lvbikgYW5kIGFyZSBub3Qgc3RhdGlzdGljYWxseQogICAgIysgc2lnbmlmaWNhbnQ7IHRoaXMgdmVjdG9yIHNpZ25pZmllcyBmZWF0dXJlcyB0aGF0IGFyZSAic3RhYmx5IGV4cHJlc3NlZCIKICAgICMrIGJldHdlZW4gY29uZGl0aW9ucwogICAgdGJsJHN0YWJseV9leHByZXNzZWQgPC0gaWZlbHNlKAogICAgICAgICFpcy5uYSh0YmwkdGhyZXNob2xkKSAmIHRibCRwYWRqID4gMC4wNSwKICAgICAgICBUUlVFLAogICAgICAgIEZBTFNFCiAgICApCiAgICBzdGFibHlfZXhwcmVzc2VkX0tMIDwtIHRibCRmZWF0dXJlW3RibCRzdGFibHlfZXhwcmVzc2VkID09IFRSVUVdCiAgICAKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA3ZF90YmwiXV0gPC0gdGJsCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wN2RfdGl0bGUiXV0gPC0gdGl0bGUKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA3ZF9zdWJ0aXRsZSJdXSA8LSBzdWJ0aXRsZQogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDdkX01BX0tMIl1dIDwtIE1BX0tMCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wN2Rfc3RhYmx5X2V4cHJlc3NlZF9LTCJdXSA8LSBzdGFibHlfZXhwcmVzc2VkX0tMCiAgICAKICAgIHJtKHRibCwgdGl0bGUsIHN1YnRpdGxlKQogICAgCiAgICAjICA3ZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgN2UuIE1ha2UgYSB2b2xjYW5vIHBsb3RcblxuIgogICAgKSkKICAgIAogICAgIyAgSWRlbnRpZnkgYW5kIGlzb2xhdGUgdGhlIHRvcCA1IHVwcmVndWxhdGVkIGZlYXR1cmVzIGFuZCB0aGUgdG9wIDUgZG93bi0KICAgICMrIHJlZ3VsYXRlZCBmZWF0dXJlcwogICAgYWxsIDwtIHRfREdFX0tMJGZlYXR1cmUKICAgIHNlbGVjdGlvbl9kb3duIDwtIHRfREdFX0tMICU+JQogICAgICAgIGRwbHlyOjpmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPCAwKSAlPiUKICAgICAgICBkcGx5cjo6YXJyYW5nZShwYWRqKSAlPiUKICAgICAgICBkcGx5cjo6c2xpY2UoMTo1KQogICAgc2VsZWN0aW9uX3VwIDwtIHRfREdFX0tMICU+JQogICAgICAgIGRwbHlyOjpmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPiAwKSAlPiUKICAgICAgICBkcGx5cjo6YXJyYW5nZShwYWRqKSAlPiUKICAgICAgICBkcGx5cjo6c2xpY2UoMTo1KQogICAgc2VsZWN0aW9uIDwtIGMoc2VsZWN0aW9uX2Rvd25bWyJmZWF0dXJlIl1dLCBzZWxlY3Rpb25fdXBbWyJmZWF0dXJlIl1dKSAlPiUKICAgICAgICAgICAgYXMuY2hhcmFjdGVyKCkKICAgIAogICAgdGl0bGUgPC0gcGFzdGUwKAogICAgICAgICJ2b2xjYW5vIHBsb3QgfCBLLiBsYWN0aXMgZmVhdHVyZXMgfFxuIiwKICAgICAgICAic2l6ZSBmYWN0b3JzIGVzdGltYXRlZCB3aXRoIGFsbCBLLiBsYWN0aXMgZmVhdHVyZXMiCiAgICApCiAgICBzdWJ0aXRsZSA8LSBwYXN0ZSgKICAgICAgICAicG9pbnRzOiBLLiBsYWN0aXMgZmVhdHVyZXMiLAogICAgICAgICJ8IGxlZnQ6IHVwIGluIiwgbW9kZWxfZCwKICAgICAgICAifCByaWdodDogdXAgaW4iLCBtb2RlbF9uLAogICAgICAgICJ8XG5sYWJlbHM6IHRvcCA1IiwgbW9kZWxfZCwgImFuZCB0b3AgNSIsIG1vZGVsX24sICJmZWF0dXJlcyIKICAgICkgICMgWzFdICJzdHJhaW5fby5kX3ZzX24zLmQiCiAgICB2b2xjYW5vX0tMIDwtIHBsb3Rfdm9sY2FubygKICAgICAgICB0YWJsZSA9IHRfREdFX0tMLAogICAgICAgIGxhYmVsID0gYWxsLAogICAgICAgIHNlbGVjdGlvbiA9IHNlbGVjdGlvbiwKICAgICAgICBsYWJlbF9zaXplID0gMi41LAogICAgICAgIHBfY3V0b2ZmID0gMC4wNSwKICAgICAgICBGQ19jdXRvZmYgPSAxLAogICAgICAgIHhsaW0gPSBjKC0xNCwgMTQpLAogICAgICAgIHlsaW0gPSBjKDAsIDEwKSwKICAgICAgICAjIHlsaW0gPSBjKDAsIDMxMCksCiAgICAgICAgY29sb3IgPSAiIzUyQkU5QiIsCiAgICAgICAgdGl0bGUgPSB0aXRsZSwKICAgICAgICBzdWJ0aXRsZSA9IHN1YnRpdGxlCiAgICApCiAgICB2b2xjYW5vX0tMCiAgICAjIHNhdmVfdm9sY2FubygKICAgICMgICAgIGZpbGUgPSAidGVzdC5wZGYiLAogICAgIyAgICAgcGxvdCA9IHAsCiAgICAjICAgICB3aWR0aCA9IDIsCiAgICAjICAgICBoZWlnaHQgPSAzCiAgICAjICkKICAgIAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDdlX2FsbCJdXSA8LSBhbGwKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA3ZV9zZWxlY3Rpb25fZG93biJdXSA8LSBzZWxlY3Rpb25fZG93bgogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDdlX3NlbGVjdGlvbl91cCJdXSA8LSBzZWxlY3Rpb25fdXAKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA3ZV9zZWxlY3Rpb24iXV0gPC0gc2VsZWN0aW9uCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wN2VfdGl0bGUiXV0gPC0gdGl0bGUKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA3ZV9zdWJ0aXRsZSJdXSA8LSBzdWJ0aXRsZQogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDdlX3ZvbGNhbm9fS0wiXV0gPC0gdm9sY2Fub19LTAogICAgCiAgICBybShhbGwsIHNlbGVjdGlvbiwgc2VsZWN0aW9uX3VwLCBzZWxlY3Rpb25fZG93biwgdGl0bGUsIHN1YnRpdGxlKQogICAgCiAgICAjICA4IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgOC4gUnVuIERFIGFuYWx5c2VzIGZvciAnIiwgbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXSwKICAgICAgICAiJywgZXhhbWluaW5nIFMuIGNlcmV2aXNpYWUgZmVhdHVyZXMgYW5kICIsCiAgICAgICAgInVzaW5nIEsuIGxhY3RpcyBmZWF0dXJlcyBmb3Igc2l6ZS1mYWN0b3IgZXN0aW1hdGlvblxuXG4iCiAgICApKQogICAgCiAgICAjICA4YSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgOGEuIFBlcmZvcm0gc2l6ZS1mYWN0b3IgZXN0aW1hdGlvblxuXG4iCiAgICApKQogICAgCiAgICBkZHNfU0MuY3RybF9LTCA8LSBCaW9jR2VuZXJpY3M6OmVzdGltYXRlU2l6ZUZhY3RvcnMoCiAgICAgICAgZGRzLAogICAgICAgIGNvbnRyb2xHZW5lcyA9IChkZHNAcm93UmFuZ2VzJGdlbm9tZSA9PSAiS19sYWN0aXMiKQogICAgKQogICAgZGRzX1NDLmN0cmxfS0xAY29sRGF0YQogICAgCiAgICAjVE9ETyBQcmludCBhbmQgc2F2ZSBzb21lIGJyaWVmIHRhYmxlIG9mIHNhbXBsZSBhbmQgc2l6ZSBmYWN0b3IKICAgIHNmX3NhbXBsZXMgPC0gZGRzX1NDLmN0cmxfS0wkc2l6ZUZhY3RvciAlPiUgbmFtZXMoKSAlPiUgdGliYmxlOjphc190aWJibGUoKQogICAgc2ZfdmFsdWVzIDwtIGRkc19TQy5jdHJsX0tMJHNpemVGYWN0b3IgJT4lIHRpYmJsZTo6YXNfdGliYmxlKCkKICAgIHNmX3RibF9TQy5jdHJsX0tMIDwtIGRwbHlyOjpiaW5kX2NvbHMoc2Zfc2FtcGxlcywgc2ZfdmFsdWVzKQogICAgY29sbmFtZXMoc2ZfdGJsX1NDLmN0cmxfS0wpIDwtIGMoInNhbXBsZXMiLCAic2l6ZV9mYWN0b3JzIikKICAgIHJtKHNmX3NhbXBsZXMsIHNmX3ZhbHVlcykKICAgIAogICAgIyBwcmludChzZl90YmxfU0MuY3RybF9LTCwgbiA9IG5yb3coc2ZfdGJsX1NDLmN0cmxfS0wpKQogICAgCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGFfZGRzX1NDLmN0cmxfS0wiXV0gPC0gZGRzX1NDLmN0cmxfS0wKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA4YV9zZl90YmxfU0MuY3RybF9LTCJdXSA8LSBzZl90YmxfU0MuY3RybF9LTAogICAgCiAgICAjICA4YiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgY2F0KHBhc3RlMCgKICAgICAgICAiIysgOGIuIENhbGwgREVTZXEyIHVzaW5nIGRlZmF1bHQgcGFyYW1ldGVyc1xuXG4iCiAgICApKQogICAgCiAgICBkZHNfU0MuY3RybF9LTCA8LSBERVNlcTI6OkRFU2VxKGRkc19TQy5jdHJsX0tMKQogICAgCiAgICAjICBDaGVjayBtb2RlbCBpbmZvcm1hdGlvbgogICAgY2F0KHBhc3RlMCgKICAgICAgICAiREVTZXEyIG1vZGVsIGluZm9ybWF0aW9uOiAnIiwKICAgICAgICBERVNlcTI6OnJlc3VsdHNOYW1lcyhkZHNfU0MuY3RybF9LTClbMl0sICInXG5cbiIsCiAgICAgICAgIlRodXMsIHRoZSBtb2RlbCB2YXJpZXMgb24gc3RyYWluLCB0aGUgbGVmdCBzYW1wbGUgaXMgdGhlIG51bWVyYXRvciwgIiwKICAgICAgICAidGhlIHJpZ2h0IHNhbXBsZSBpcyB0aGUgZGVub21pbmF0b3JcbiIsCiAgICAgICAgIiAgICAtIE51bWVyYXRvcjogdG9wIGluIE1BIHBsb3RzLCByaWdodCBpbiB2b2xjYW5vIHBsb3RzXG4iLAogICAgICAgICIgICAgLSBEZW5vbWluYXRvcjogYm90dG9tIGluIE1BIHBsb3RzLCBsZWZ0IGluIHZvbGNhbm8gcGxvdHNcblxuIgogICAgKSkKICAgIAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDhiX2Rkc19TQy5jdHJsX0tMIl1dIDwtIGRkc19TQy5jdHJsX0tMCgogICAgIyAgOGMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIGNhdChwYXN0ZTAoCiAgICAgICAgIiMrIDhjLiBDYWxsIERFU2VxMjo6cmVzdWx0cygpXG5cbiIKICAgICkpCiAgICAKICAgICMgIFNldCB1cCBuZWNlc3NhcnkgcGFyYW1ldGVycyBmb3IgZ2VuZXJhdGlvbiBvZiBERVNlcTIgcmVzdWx0cyB0YWJsZQogICAgaW5kZXBlbmRlbnRfZmlsdGVyaW5nIDwtIFRSVUUKICAgIHRocmVzaG9sZF9wIDwtIDAuMDUKICAgIHRocmVzaG9sZF9sZmMgPC0gMAogICAgCiAgICBjYXQocGFzdGUwKAogICAgICAgICIgICAgaW5kZXBlbmRlbnRfZmlsdGVyaW5nICAiLCBpbmRlcGVuZGVudF9maWx0ZXJpbmcsICJcbiIsCiAgICAgICAgIiAgICAgICAgICAgICAgdGhyZXNob2xkX3AgICIsIHRocmVzaG9sZF9wLCAiXG4iLAogICAgICAgICIgICAgICAgICAgICB0aHJlc2hvbGRfbGZjICAiLCB0aHJlc2hvbGRfbGZjLCAiXG5cbiIKICAgICkpCiAgICAKICAgICMgIE91dHB1dCBhIERFU2VxMiBEYXRhRnJhbWUgb2JqZWN0CiAgICBER0VfdW5zaHJ1bmtlbl9ERl9TQy5jdHJsX0tMIDwtIERFU2VxMjo6cmVzdWx0cygKICAgICAgICBkZHNfU0MuY3RybF9LTCwKICAgICAgICBuYW1lID0gREVTZXEyOjpyZXN1bHRzTmFtZXMoZGRzX1NDLmN0cmxfS0wpWzJdLAogICAgICAgIGluZGVwZW5kZW50RmlsdGVyaW5nID0gaW5kZXBlbmRlbnRfZmlsdGVyaW5nLAogICAgICAgIGFscGhhID0gdGhyZXNob2xkX3AsCiAgICAgICAgbGZjVGhyZXNob2xkID0gdGhyZXNob2xkX2xmYywKICAgICAgICBmb3JtYXQgPSAiRGF0YUZyYW1lIgogICAgKQogICAgCiAgICAjICBPdXRwdXQgYSBHUmFuZ2VzIG9iamVjdCwgd2hpY2ggd2UgY2FuIGVhc2lseSBhZGQgdG8gYW5kIGNvbnZlcnQgdG8gb3RoZXIKICAgICMrIGZvcm1hdHMgKHN1Y2ggYXMgYSB0aWJibGUpCiAgICBER0VfdW5zaHJ1bmtlbl9HUl9TQy5jdHJsX0tMIDwtIERFU2VxMjo6cmVzdWx0cygKICAgICAgICBkZHNfU0MuY3RybF9LTCwKICAgICAgICBuYW1lID0gREVTZXEyOjpyZXN1bHRzTmFtZXMoZGRzX1NDLmN0cmxfS0wpWzJdLAogICAgICAgIGluZGVwZW5kZW50RmlsdGVyaW5nID0gaW5kZXBlbmRlbnRfZmlsdGVyaW5nLAogICAgICAgIGFscGhhID0gdGhyZXNob2xkX3AsCiAgICAgICAgbGZjVGhyZXNob2xkID0gdGhyZXNob2xkX2xmYywKICAgICAgICBmb3JtYXQgPSAiR1JhbmdlcyIKICAgICkKICAgIERHRV91bnNocnVua2VuX0dSX1NDLmN0cmxfS0wkbGVuZ3RoIDwtIE1hdHJpeEdlbmVyaWNzOjpyb3dSYW5nZXMoCiAgICAgICAgZGRzX1NDLmN0cmxfS0wKICAgICkkbGVuZ3RoCiAgICBER0VfdW5zaHJ1bmtlbl9HUl9TQy5jdHJsX0tMJGZlYXR1cmUgPC0gTWF0cml4R2VuZXJpY3M6OnJvd1JhbmdlcygKICAgICAgICBkZHNfU0MuY3RybF9LTAogICAgKSRmZWF0dXJlCiAgICBER0VfdW5zaHJ1bmtlbl9HUl9TQy5jdHJsX0tMJGZlYXR1cmVfaW5pdCA8LSBNYXRyaXhHZW5lcmljczo6cm93UmFuZ2VzKAogICAgICAgIGRkc19TQy5jdHJsX0tMCiAgICApJGZlYXR1cmVfaW5pdAogICAgREdFX3Vuc2hydW5rZW5fR1JfU0MuY3RybF9LTCR0eXBlIDwtIE1hdHJpeEdlbmVyaWNzOjpyb3dSYW5nZXMoCiAgICAgICAgZGRzX1NDLmN0cmxfS0wKICAgICkkdHlwZQogICAgREdFX3Vuc2hydW5rZW5fR1JfU0MuY3RybF9LTCRnZW5vbWUgPC0gTWF0cml4R2VuZXJpY3M6OnJvd1JhbmdlcygKICAgICAgICBkZHNfU0MuY3RybF9LTAogICAgKSRnZW5vbWUKICAgIAogICAgdF9ER0VfU0MuY3RybF9LTCA8LSBER0VfdW5zaHJ1bmtlbl9HUl9TQy5jdHJsX0tMICU+JQogICAgICAgIGRwbHlyOjphc190aWJibGUoKSAlPiUKICAgICAgICBkcGx5cjo6cmVuYW1lKGNociA9IHNlcW5hbWVzKQogICAgCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGNfaW5kZXBlbmRlbnRfZmlsdGVyaW5nIl1dIDwtIGluZGVwZW5kZW50X2ZpbHRlcmluZwogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDhjX3RocmVzaG9sZF9wIl1dIDwtIHRocmVzaG9sZF9wCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGNfdGhyZXNob2xkX2xmYyJdXSA8LSB0aHJlc2hvbGRfbGZjCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGNfREdFX3Vuc2hydW5rZW5fREZfU0MuY3RybF9LTCJdXSA8LSBER0VfdW5zaHJ1bmtlbl9ERl9TQy5jdHJsX0tMCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGNfREdFX3Vuc2hydW5rZW5fR1JfU0MuY3RybF9LTCJdXSA8LSBER0VfdW5zaHJ1bmtlbl9HUl9TQy5jdHJsX0tMCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGNfdF9ER0VfU0MuY3RybF9LTCJdXSA8LSB0X0RHRV9TQy5jdHJsX0tMCiAgICAKICAgIHJtKGluZGVwZW5kZW50X2ZpbHRlcmluZywgdGhyZXNob2xkX3AsIHRocmVzaG9sZF9sZmMpCiAgICAKICAgICMgIDhkIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBjYXQocGFzdGUwKAogICAgICAgICIjKyA4ZC4gTWFrZSBhbiBNQSBwbG90IHRoYXQgY29sb3JzIGZlYXR1cmVzIGJ5ICIsCiAgICAgICAgImluZGVwZW5kZW50IGZpbHRlcmluZ1xuXG4iCiAgICApKQogICAgCiAgICAjICBTZXQgdXAgdGVtcG9yYXJ5IHZhcmlhYmxlICd0YmwnLCB3aGljaCB3aWxsIGJlIHBhc3NlZCB0byBnZ3Bsb3QKICAgIHRibCA8LSB0X0RHRV9TQy5jdHJsX0tMCiAgICB0YmwgPC0gdGJsW3dpdGgodGJsLCBvcmRlcihsb2cyRm9sZENoYW5nZSkpLCBdCiAgICB0YmwkdGhyZXNob2xkIDwtIGFzLmZhY3Rvcih0YmwkcGFkaiA8PSAwLjA1KQogICAgdGJsJGxvZzEwYmFzZU1lYW4gPC0gaWZlbHNlKAogICAgICAgIGlzLmluZmluaXRlKGxvZzEwKHRibCRiYXNlTWVhbikpLCBOQSwgbG9nMTAodGJsJGJhc2VNZWFuKQogICAgKQogICAgCiAgICB0aXRsZSA8LSBwYXN0ZTAoCiAgICAgICAgIk1BIHBsb3QgfCBTLiBjZXJldmlzaWFlIGZlYXR1cmVzIHxcbiIsCiAgICAgICAgInNpemUgZmFjdG9ycyBlc3RpbWF0ZWQgd2l0aCBhbGwgSy4gbGFjdGlzIGZlYXR1cmVzIgogICAgKQogICAgc3VidGl0bGUgPC0gcGFzdGUoCiAgICAgICAgInBvaW50czogUy4gY2VyZXZpc2lhZSBmZWF0dXJlcyIsCiAgICAgICAgInwgdG9wOiB1cCBpbiIsIG1vZGVsX24sCiAgICAgICAgInwgYm90dG9tOiB1cCBpbiIsIG1vZGVsX2QKICAgICkgICMgWzFdICJzdHJhaW5fby5kX3ZzX24zLmQiCiAgICBNQV9TQy5jdHJsX0tMIDwtIGdncGxvdCgKICAgICAgICB0YmwsIGFlcyh4ID0gbG9nMTBiYXNlTWVhbiwgeSA9IGxvZzJGb2xkQ2hhbmdlLCBjb2xvdXIgPSB0aHJlc2hvbGQpCiAgICApICsKICAgICAgICBnZW9tX3BvaW50KGFscGhhID0gMC4yNSwgc2l6ZSA9IDAuNSkgKwogICAgICAgICMgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDApLCBjb2xvdXIgPSAiIzAwMDAwMCIsIGxpbmV3aWR0aCA9IDAuMjUpICsKICAgICAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMCksIGNvbG91ciA9ICIjMDAwMDAwIiwgc2l6ZSA9IDAuMjUpICsKICAgICAgICAjIHlsaW0oYyhtaW4odGJsJGxvZzJGb2xkQ2hhbmdlKSwgbWF4KHRibCRsb2cyRm9sZENoYW5nZSkpKSArCiAgICAgICAgeWxpbShjKC0xNCwgMTQpKSArCiAgICAgICAgeGxhYigibG9nMTAobWVhbiBub3JtYWxpemVkIGNvdW50cykiKSArCiAgICAgICAgeWxhYigibG9nMihmb2xkIGNoYW5nZSkiKSArCiAgICAgICAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKG5hbWUgPSAicSDiiaQgMC4wNSIpICsKICAgICAgICBnZ3RpdGxlKHRpdGxlLCBzdWJ0aXRsZSkgKwogICAgICAgIHRoZW1lX3NsaWNrCiAgICBNQV9TQy5jdHJsX0tMCiAgICAjVE9ETyAxLzIgRXhwbGFpbiBhbmQgbWFrZSBhIGRlY2lzaW9uIHJlZ2FyZGluZyB1c2Ugb2YgJ3NpemUnIG9yICdsaW5ld2lkdGgnCiAgICAjVE9ETyAyLzIgcGFyYW1ldGVycwogICAgCiAgICAjICBDcmVhdGUgYSB2ZWN0b3Igb2YgZmVhdHVyZXMgdGhhdCBib3RoIHBhc3NlZCBpbmRlcGVuZGVudCBmaWx0ZXJpbmcgKGFuZCB0aHVzCiAgICAjKyBoYXZlIGFuIGluaGVyZW50bHkgaGlnaCBtZWFuIGV4cHJlc3Npb24pIGFuZCBhcmUgbm90IHN0YXRpc3RpY2FsbHkKICAgICMrIHNpZ25pZmljYW50OyB0aGlzIHZlY3RvciBzaWduaWZpZXMgZmVhdHVyZXMgdGhhdCBhcmUgInN0YWJseSBleHByZXNzZWQiCiAgICAjKyBiZXR3ZWVuIGNvbmRpdGlvbnMKICAgIHRibCRzdGFibHlfZXhwcmVzc2VkIDwtIGlmZWxzZSgKICAgICAgICAhaXMubmEodGJsJHRocmVzaG9sZCkgJiB0YmwkcGFkaiA+IDAuMDUsCiAgICAgICAgVFJVRSwKICAgICAgICBGQUxTRQogICAgKQogICAgc3RhYmx5X2V4cHJlc3NlZF9TQy5jdHJsX0tMIDwtIHRibCRmZWF0dXJlW3RibCRzdGFibHlfZXhwcmVzc2VkID09IFRSVUVdCiAgICAKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA4ZF90YmwiXV0gPC0gdGJsCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGRfdGl0bGUiXV0gPC0gdGl0bGUKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA4ZF9zdWJ0aXRsZSJdXSA8LSBzdWJ0aXRsZQogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDhkX01BX1NDLmN0cmxfS0wiXV0gPC0gTUFfU0MuY3RybF9LTAogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDhkX3N0YWJseV9leHByZXNzZWRfU0MuY3RybF9LTCJdXSA8LSBzdGFibHlfZXhwcmVzc2VkX1NDLmN0cmxfS0wKICAgIAogICAgcm0odGJsLCB0aXRsZSwgc3VidGl0bGUpCiAgICAKICAgICMgIDhlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBjYXQocGFzdGUwKAogICAgICAgICIjKyA4ZS4gTWFrZSBhIHZvbGNhbm8gcGxvdFxuXG4iCiAgICApKQogICAgCiAgICAjICBJZGVudGlmeSBhbmQgaXNvbGF0ZSB0aGUgdG9wIDUgdXByZWd1bGF0ZWQgZmVhdHVyZXMgYW5kIHRoZSB0b3AgNSBkb3duLQogICAgIysgcmVndWxhdGVkIGZlYXR1cmVzCiAgICBhbGwgPC0gdF9ER0VfU0MuY3RybF9LTCRmZWF0dXJlCiAgICBzZWxlY3Rpb25fZG93biA8LSB0X0RHRV9TQy5jdHJsX0tMICU+JQogICAgICAgIGRwbHlyOjpmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPCAwKSAlPiUKICAgICAgICBkcGx5cjo6YXJyYW5nZShwYWRqKSAlPiUKICAgICAgICBkcGx5cjo6c2xpY2UoMTo1KQogICAgc2VsZWN0aW9uX3VwIDwtIHRfREdFX1NDLmN0cmxfS0wgJT4lCiAgICAgICAgZHBseXI6OmZpbHRlcihsb2cyRm9sZENoYW5nZSA+IDApICU+JQogICAgICAgIGRwbHlyOjphcnJhbmdlKHBhZGopICU+JQogICAgICAgIGRwbHlyOjpzbGljZSgxOjUpCiAgICBzZWxlY3Rpb24gPC0gYyhzZWxlY3Rpb25fZG93bltbImZlYXR1cmUiXV0sIHNlbGVjdGlvbl91cFtbImZlYXR1cmUiXV0pICU+JQogICAgICAgICAgICBhcy5jaGFyYWN0ZXIoKQogICAgCiAgICB0aXRsZSA8LSBwYXN0ZTAoCiAgICAgICAgInZvbGNhbm8gcGxvdCB8IFMuIGNlcmV2aXNpYWUgZmVhdHVyZXMgfFxuIiwKICAgICAgICAic2l6ZSBmYWN0b3JzIGVzdGltYXRlZCB3aXRoIGFsbCBLLiBsYWN0aXMgZmVhdHVyZXMiCiAgICApCiAgICBzdWJ0aXRsZSA8LSBwYXN0ZSgKICAgICAgICAicG9pbnRzOiBTLiBjZXJldmlzaWFlIGZlYXR1cmVzIiwKICAgICAgICAifCBsZWZ0OiB1cCBpbiIsIG1vZGVsX2QsCiAgICAgICAgInwgcmlnaHQ6IHVwIGluIiwgbW9kZWxfbiwKICAgICAgICAifFxubGFiZWxzOiB0b3AgNSIsIG1vZGVsX2QsICJhbmQgdG9wIDUiLCBtb2RlbF9uLCAiZmVhdHVyZXMiCiAgICApICAjIFsxXSAic3RyYWluX28uZF92c19uMy5kIgogICAgdm9sY2Fub19TQy5jdHJsX0tMIDwtIHBsb3Rfdm9sY2FubygKICAgICAgICB0YWJsZSA9IHRfREdFX1NDLmN0cmxfS0wsCiAgICAgICAgbGFiZWwgPSBhbGwsCiAgICAgICAgc2VsZWN0aW9uID0gc2VsZWN0aW9uLAogICAgICAgIGxhYmVsX3NpemUgPSAyLjUsCiAgICAgICAgcF9jdXRvZmYgPSAwLjA1LAogICAgICAgIEZDX2N1dG9mZiA9IDEsCiAgICAgICAgeGxpbSA9IGMoLTE0LCAxNCksCiAgICAgICAgeWxpbSA9IGMoMCwgMTApLAogICAgICAgICMgeWxpbSA9IGMoMCwgMzEwKSwKICAgICAgICBjb2xvciA9ICIjNTJCRTlCIiwKICAgICAgICB0aXRsZSA9IHRpdGxlLAogICAgICAgIHN1YnRpdGxlID0gc3VidGl0bGUKICAgICkKICAgIHZvbGNhbm9fU0MuY3RybF9LTAogICAgIyBzYXZlX3ZvbGNhbm8oCiAgICAjICAgICBmaWxlID0gInRlc3QucGRmIiwKICAgICMgICAgIHBsb3QgPSBwLAogICAgIyAgICAgd2lkdGggPSAyLAogICAgIyAgICAgaGVpZ2h0ID0gMwogICAgIyApCiAgICAKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA4ZV9hbGwiXV0gPC0gYWxsCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGVfc2VsZWN0aW9uX2Rvd24iXV0gPC0gc2VsZWN0aW9uX2Rvd24KICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA4ZV9zZWxlY3Rpb25fdXAiXV0gPC0gc2VsZWN0aW9uX3VwCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGVfc2VsZWN0aW9uIl1dIDwtIHNlbGVjdGlvbgogICAgcmVzW1tuYW1lcyhkYXRhc2V0c19ncm91cGVkKVtbaV1dXV1bWyJuMDhlX3RpdGxlIl1dIDwtIHRpdGxlCiAgICByZXNbW25hbWVzKGRhdGFzZXRzX2dyb3VwZWQpW1tpXV1dXVtbIm4wOGVfc3VidGl0bGUiXV0gPC0gc3VidGl0bGUKICAgIHJlc1tbbmFtZXMoZGF0YXNldHNfZ3JvdXBlZClbW2ldXV1dW1sibjA4ZV92b2xjYW5vX1NDLmN0cmxfS0wiXV0gPC0gdm9sY2Fub19TQy5jdHJsX0tMCiAgICAKICAgIHJtKGFsbCwgc2VsZWN0aW9uLCBzZWxlY3Rpb25fdXAsIHNlbGVjdGlvbl9kb3duLCB0aXRsZSwgc3VidGl0bGUpCn0KYGBgCjxiciAvPgoKYGBge3J9CiMgIE1BIHBsb3RzCnJlcyRkYXRhc2V0c19yMV9yNiRuMDZkX01BX1NDCnJlcyRkYXRhc2V0c19XVF9yNiRuMDZkX01BX1NDCnJlcyRkYXRhc2V0c19XVF9yMSRuMDZkX01BX1NDCgpyZXMkZGF0YXNldHNfcjFfcjYkbjA3ZF9NQV9LTApyZXMkZGF0YXNldHNfV1RfcjYkbjA3ZF9NQV9LTApyZXMkZGF0YXNldHNfV1RfcjEkbjA3ZF9NQV9LTAoKcmVzJGRhdGFzZXRzX3IxX3I2JG4wOGRfTUFfU0MuY3RybF9LTApyZXMkZGF0YXNldHNfV1RfcjYkbjA4ZF9NQV9TQy5jdHJsX0tMCnJlcyRkYXRhc2V0c19XVF9yMSRuMDhkX01BX1NDLmN0cmxfS0wKCiMgIFZvbGNhbm8gcGxvdHMKcmVzJGRhdGFzZXRzX3IxX3I2JG4wNmVfdm9sY2Fub19TQwpyZXMkZGF0YXNldHNfV1RfcjYkbjA2ZV92b2xjYW5vX1NDCnJlcyRkYXRhc2V0c19XVF9yMSRuMDZlX3ZvbGNhbm9fU0MKCnJlcyRkYXRhc2V0c19yMV9yNiRuMDdlX3ZvbGNhbm9fS0wKcmVzJGRhdGFzZXRzX1dUX3I2JG4wN2Vfdm9sY2Fub19LTApyZXMkZGF0YXNldHNfV1RfcjEkbjA3ZV92b2xjYW5vX0tMCgpyZXMkZGF0YXNldHNfcjFfcjYkbjA4ZV92b2xjYW5vX1NDLmN0cmxfS0wKcmVzJGRhdGFzZXRzX1dUX3I2JG4wOGVfdm9sY2Fub19TQy5jdHJsX0tMCnJlcyRkYXRhc2V0c19XVF9yMSRuMDhlX3ZvbGNhbm9fU0MuY3RybF9LTApgYGAKPGJyIC8+Cg==